How to interpolate at NaN values?

216 views (last 30 days)
Mr M.
Mr M. on 30 Jun 2018
Edited: Stephen23 on 8 Dec 2020
I have a vector [1 2 3 NaN 4 4.5 5.5 NaN NaN 6 6 7 NaN NaN NaN 8] and I want [1 2 3 3.5 4 4.5 5.5 5.75 5.75 6 6 7 7.5 7.5 7.5 8]. Is it possible to do this without a for cycle?
  2 Comments
jonas
jonas on 30 Jun 2018
Yes, see previous question here ( link )
Paolo
Paolo on 30 Jun 2018
Is it really interpolation? Whenever you have three consecutive NaN they all have the same value.

Sign in to comment.

Accepted Answer

Stephen23
Stephen23 on 30 Jun 2018
Edited: Stephen23 on 30 Jun 2018
No loops, no third-party functions, and works for all MATLAB versions:
>> V = [1 2 3 NaN 4 4.5 5.5 NaN NaN 6 6 7 NaN NaN NaN 8];
>> X = ~isnan(V);
>> Y = cumsum(X-diff([1,X])/2);
>> Z = interp1(1:nnz(X),V(X),Y)
Z = 1.00 2.00 3.00 3.50 4.00 4.50 5.50 5.75 5.75 6.00 6.00 7.00 7.50 7.50 7.50 8.00
  2 Comments
Fernand ASSENE
Fernand ASSENE on 7 Dec 2020
Hello Dear Stephen,
First thank for sharing.
I have the problem with your code when matrix begins with nan values, it does not work.
Please do you how can i fix this issue???
Stephen23
Stephen23 on 7 Dec 2020
Edited: Stephen23 on 8 Dec 2020
@Fernand ASSENE: in the original question all NaN were replaced by the average of the two non-NaN values on either side. If you have a NaN at the start then there are no such two values and so you will have to be more specific about what you expect to be returned, e.g.:
  1. the first non-NaN value
  2. a value extrapolated from the first two or more non-NaN values.
  3. something else...
Note that none of these are the same as the original rule, nor is any of them "better" than the others, so I cannot guess which output you want. Consider the example in the original question appended with NaN i.e. [NaN,1,2,3,NaN,4...], what would you expect the first output value to be?:
  1. 1
  2. 0
  3. something else...

Sign in to comment.

More Answers (2)

Jan
Jan on 30 Jun 2018
Edited: Jan on 30 Jun 2018
a = [1 2 3 NaN 4 4.5 5.5 NaN NaN 6 6 7 NaN NaN NaN 8];
b = 0.5 * (fillmissing(a, 'previous') + fillmissing(a, 'next'))
Or
v = ~isnan(a);
G = griddedInterpolant(find(v), a(v), 'previous');
idx = find(~v);
bp = G(idx);
G.Method = 'next';
bn = G(idx);
b = a;
b(idx) = (bp + bn) / 2;
Some timings:
n = 20;
a = rand(1, 1e6);
a(rand(1, 1e6) < 0.3) = NaN;
tic
for k = 1:n
b = 0.5 * (fillmissing(a, 'previous') + fillmissing(a, 'next'));
end
toc
tic;
for k = 1:n
v = ~isnan(a);
G = griddedInterpolant(find(v), a(v), 'previous');
idx = find(~v);
bp = G(idx);
G.Method = 'next';
bn = G(idx);
b = a;
b(idx) = (bp + bn) / 2;
end
toc
tic;
for k = 1:n
X = ~isnan(a);
Y = cumsum(X-diff([1,X])/2);
b = interp1(1:nnz(X),a(X),Y);
end
toc
R2016b, i7:
Elapsed time is 2.901105 seconds.
Elapsed time is 0.598722 seconds.
Elapsed time is 1.032346 seconds.

Syed Abdul Salam
Syed Abdul Salam on 4 Sep 2019
Why not use smooth function with 2 levels, it will result the same as mentioned in accepted answer.
V = [1 2 3 NaN 4 4.5 5.5 NaN NaN 6 6 7 NaN NaN NaN 8];
Z = smooth(V,2)
Z = [1 2 3 3.500 4 4.500 5.500 5.500 6 6 6 7 7 7.500 8 8]

Categories

Find more on Interpolation of 2-D Selections in 3-D Grids in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!