How to I interpolate only if 5 or less missing data next to each other?

4 views (last 30 days)
Hi,
I have an array of data, I want to interpolate NaNs over columns but only if there is 5 or less consecutive NaNs in a column.
I was thinking of using isnan function, and then marking places where I need to interpolate, but I'm not sure exactly how to do that.
Any ideas are welcom :) Thanks!
K.

Accepted Answer

Jan
Jan on 14 Sep 2013
Edited: Jan on 14 Sep 2013
[b, n] = RunLength(isnan(x));
shortNaN = RunLength(b & (n < 5), n);
x(shortNaN) = interp1(find(~shortNaN), x(~shortNaN), find(shortNaN), 'linear');
INTERP1 shows a warning then:
Warning: NaN found in Y, interpolation at undefined values
will result in undefined values.
But it is not possible that the NaN's appear in the output of the interpolation in this case and therefore the warning is misleading. To avoid it, you can either use a much faster replacement of INTERP1, see e.g. http://www.mathworks.com/matlabcentral/answers/64118#answer_75899 . Or you can interpolate on all NaNs at first and overwrite the long runs afterwards:
index = isnan(x);
x(index) = interp1(find(~index), x(~index), find(index), 'linear');
[b, n] = RunLength(index);
longRun = RunLength(b & (n > 4), n);
x(longRun) = NaN;
  4 Comments
Dolly More
Dolly More on 11 Mar 2021
Does it work for a matrix array? I tried on a 389 x 1800 matrix. I am getting the following error.
Error using RunLength_M (line 81)
*** RunLength[m]: 1st input must be a row or column vector.
Also, does it only interpolate row-wise or column-wise as well?
Jan
Jan on 27 May 2021
The documentation clarifies exactly, that RunLength operates on vectors only:
help RunLength
The error message tells you the same. If you provide a vector as input, it is processed in the direction, it has: row-vectors are processed row-wise, column-vectors are processed column-wise, as usual in Matlab.
If you provide a matrix as output, each column (or row) can produce a different number of outputs. Therefore a cell array must be replied. Simply call RunLength in a loop and provide the rows or columns of your matrix.

Sign in to comment.

More Answers (2)

Chad Greene
Chad Greene on 1 Nov 2014
The interp1gap function allows you to specifiy a maximum gap length over which to interpolate.

Image Analyst
Image Analyst on 13 Sep 2013
And if the run of nans is longer than 5, just leave them as nans? Do you have the Image Processing Toolbox, which makes it easy to find runs of certain lengths?
  3 Comments
Image Analyst
Image Analyst on 14 Sep 2013
You can start with something like this:
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 20;
% Make signal
t = linspace(0,360, 50);
signal = sind(t);
subplot(2,2,1);
plot(t, signal, 'bo-', 'LineWidth', 2);
grid on;
title('Perfect Signal', 'FontSize', fontSize);
% Enlarge figure to full screen.
set(gcf, 'units','normalized','outerposition',[0 0.2 1 .8]);
% Add some nan's
signal([3,6,10,28]) = nan;
signal(15:20) = nan;
signal(35:41) = nan;
subplot(2,2,2);
plot(t, signal, 'bo-', 'LineWidth', 2);
grid on;
title('Actual Starting Signal with Nans', 'FontSize', fontSize);
% Get logical map of where the nans are.
nanLocations = isnan(signal)
labeledSignal = bwlabel(nanLocations)
% Find their areas
measurements = regionprops(labeledSignal, 'Area', 'PixelIdxList');
allAreas = [measurements.Area]
% Find label of those areas 5 or bigger
bigAreas = find(allAreas>=5)
% Initialize a "fixed" signal
fixedSignal = signal;
% Find indexes with that label in the original
for region = 1 : length(bigAreas)
% Get a logical vector with the location of the nans in this stretch.
badStretch = labeledSignal==bigAreas(region);
% Get the t values for them
xi = find(badStretch);
% tack on the endpoints that we will interpolate between.
xi = [xi(1)-1, xi, xi(end)+1];
leftSignalValue = signal(xi(1)-1); % Left most good point.
rightSignalValue = signal(xi(end)+1); % Right most good point.
% Linearly interpolate over that stretch.
fixedSignal(xi) = linspace(leftSignalValue, ...
rightSignalValue, length(xi));
end
% Display fixed signal
subplot(2,2, 3);
plot(t, fixedSignal, 'bo-', 'LineWidth', 2);
grid on;
title('Fixed Signal', 'FontSize', fontSize);
Roan Leeuwenburg
Roan Leeuwenburg on 27 May 2021
Edited: Roan Leeuwenburg on 27 May 2021
Thanks, I'm going to use this to test my own interpolate function. Very helpfull :)

Sign in to comment.

Categories

Find more on Resizing and Reshaping Matrices 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!