Find NaN elements (NaN-islands) in the middle of a matrix and substitute them with linearly interpolated values.
2 views (last 30 days)
Show older comments
This is repetitive 1D problem not 2D. We have a matrix (NxM) of N vectors with different length, M is the longest vector length. Shorter vectors are filled up with NaN at the end. Matrix can be big: N - 1000s, M - 100s. Sometimes vectors can have NaNs in the middle. They need to be substituted with linearly interpolated values from the nearest edges. This "NaN-islands" are rare and random.
So, for
A=[1 2 3 4 NaN 6 7 8 9 10;
10 11 12 3 7 NaN NaN 13 14 NaN;
6 8 2 5 NaN NaN NaN NaN NaN NaN;]
I would like to have
A=[1 2 3 4 5 6 7 8 9 10;
10 11 12 3 7 9 11 13 14 NaN;
6 8 2 5 NaN NaN NaN NaN NaN NaN;]
So far I have this working code but I would like to avoid at least the first loop as the biggest one and fires rarely. Any ideas?
for ind1=1:size(A,1) % loop for rows
temp=bwconncomp(isnan(A(ind1,:)));
if temp.NumObjects>1 || ~isnan(A(ind1,end)) % NaN in the middle
for ind2=1:temp.NumObjects-1+(~isnan(A(ind1,end))) % loop all NaN-islands in the row
tempCoor=temp.PixelIdxList{ind2};
tMin=min(tempCoor); % index of the first NaN point
tMax=max(tempCoor); % index of the last NaN point
tN=(tMax-tMin)+1; % number of NaN points
x=linspace(A(ind1,tMin-1),A(ind1,tMax+1),tN+2); % linear interpolation of missed values
A(ind1,tMin:tMax)=x(2:end-1);
end
end
end
Speed is more important than memory consumption.
P.s. Code contains one bug: it does not handle rows with NaN in the middle only. I have not seen such case in my data but I'll work on it in any case. -> fixed, code updated.
0 Comments
Answers (2)
Image Analyst
on 18 Dec 2015
Have you tried isnan() and regionfill() in the Image Processing Toolbox:
A=[...
1 2 3 4 NaN 6 7 8 9 10;
10 11 12 3 7 NaN NaN 13 14 NaN;
6 8 2 5 NaN NaN NaN NaN NaN NaN]
nanMap = isnan(A)
fixedA = regionfill(A, nanMap)
3 Comments
Image Analyst
on 18 Dec 2015
Then loop row-by-row and use isnan() to get a map of where NANs are and use interp1(), something like
A=[...
1 2 3 4 NaN 6 7 8 9 10;
10 11 12 3 7 NaN NaN 13 14 NaN;
6 8 2 5 NaN NaN NaN NaN NaN NaN]
[rows, columns] = size(A)
for row = 1 : rows
goodColumns = ~isnan(A(row, :));
goodA = A(row, goodColumns);
% Get the x coordinates of the good columns.
x = find(goodColumns);
fixedRow = interp1(x, goodA, 1:columns);
% Replace this row with the fixed one.
A(row, :) = fixedRow;
end
% Print Final A to command window.
A
A =
1 2 3 4 5 6 7 8 9 10
10 11 12 3 7 9 11 13 14 NaN
6 8 2 5 NaN NaN NaN NaN NaN NaN
Guillaume
on 18 Dec 2015
Edited: Guillaume
on 18 Dec 2015
This is the best scoring solution by Ly Cao (does not mean that it's the most efficient):
for i = find(isnan(x))'
x(i) = interp1(x(x==x),i-0.5);
end
Only works with a row vector, but you could adapt it.
3 Comments
Guillaume
on 10 Jul 2019
As stated: Only works with a row vector.
In any case, this is all very outdated, nowadays you'd simply use fillmissing which does it all for you.
Image Analyst
on 11 Jul 2019
Tahir, do you really have the very same problem as the original poster? (I doubt it) Why don't you post a complete description of your problem and attach your script and data, in a new separate question, so we can solve it for you?
See Also
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!