Replace NaNs with next real value.

3 views (last 30 days)
How can I replace all NaN values in an array with the next non-NaN value in the array? I have
x = [NaN 1 1 3 NaN NaN 4];
and I'd like to turn x into
x = [1 1 1 3 4 4 4];
The following works, but I'd like to do it with fewer moving parts:
for k = find(isnan(x))
x(k) = x(find(1:length(x)>k & isfinite(x),1,'first'));
end

Accepted Answer

Chad Greene
Chad Greene on 1 Nov 2014
Thanks for your suggestions, y'all. It's nice that R2014b has the 'next' and 'previous' options for 1D interpolation. I ended up writing a function to do the job in old 2012b.

More Answers (4)

Image Analyst
Image Analyst on 31 Oct 2014
I wouldn't worry about it. If it works, that way is fine. If you have millions of elements or a 2D image, then there are functions that can do it in the Image Processing Toolbox, like imfill().

Sean de Wolski
Sean de Wolski on 31 Oct 2014
Edited: Sean de Wolski on 31 Oct 2014
x = [NaN 1 1 3 NaN NaN 4];
idx = isnan(x);
idxnan = find(idx);
idxnotnan = find(~idx);
fillv = interp1([-flintmax idxnotnan],[0 x(idxnotnan)],idxnan,'next');
x(idx) = fillv;
Probably slower and harder to figure out than a for-loop and it requires R2014b; but it's cool!
  2 Comments
yogan Sganzerla
yogan Sganzerla on 25 Aug 2021
Edited: Image Analyst on 25 Aug 2021
Where was the variable flintmax defined?
Image Analyst
Image Analyst on 25 Aug 2021
@yogan Sganzerla, flintmax is built-in:
>> flintmax
ans =
9.00719925474099e+15

Sign in to comment.


per isakson
per isakson on 31 Oct 2014
Edited: per isakson on 31 Oct 2014
If &nbsp x(end) &nbsp is a number
while any( isnan( x ) )
x1 = [ x(2:end), inf ];
x( isnan(x) ) = x1( isnan(x) );
end
or
while any( isnan( x ) )
isn = isnan(x);
x( isn ) = x( [false,isn(1:end-1)] );
end
  2 Comments
yogan Sganzerla
yogan Sganzerla on 12 Jul 2021
Edited: yogan Sganzerla on 12 Jul 2021
However, if the vector is like the following, it doesn't work properly.
x = [NaN 1 1 3 NaN NaN 4 NaN NaN NaN];
Where the output will be:
[1 1 1 3 4 4 4 NaN NaN NaN]
and my intentions is to be:
[1 1 1 3 4 4 4 4 4 4].
So repeating the last real value until the end (if the vector just has NaN).
What should I add to reach this output?
Thank you for your attention.
Image Analyst
Image Analyst on 12 Jul 2021
@yogan Sganzerla, try this:
x = [NaN 1 1 3 NaN NaN 4 NaN NaN NaN]
nanIndexes = find(isnan(x))
nonNanIndexes = find(~isnan(x))
% Make any leading nans the first non nan value
if nonNanIndexes(1) ~= 1
x(1:nonNanIndexes(1) - 1) = x(nonNanIndexes(1))
end
% Make any trailing nans the last non nan value
if nonNanIndexes(end) ~= length(x)
x(nonNanIndexes(end) + 1 : end) = x(nonNanIndexes(end))
end
% Now regenerate indexes on the changes vector
nanIndexes = find(isnan(x))
nonNanIndexes = find(~isnan(x))
% Replace nan indexes with last non-nan value just prior to it.
for k = 1 : length(nanIndexes)
thisIndex = nanIndexes(k);
x(thisIndex) = x(thisIndex - 1)
end

Sign in to comment.


Roger Stafford
Roger Stafford on 31 Oct 2014
Here's another way:
t = isnan(x);
f1 = find(t);
f2 = find(diff([t,false])==-1)+1;
f3 = zeros(1,length(f1));
f3(find(diff([-1,f1])>1)) = diff([0,f2]);
f3 = cumsum(f3);
x2 = [x,x(end)];
x(f1) = x2(f3);

Community Treasure Hunt

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

Start Hunting!