Interpolation and replace zeroes

2k views Asked by At

I have 3 x n (n is random number) matrix in MATLAB. Example for n=13:

M = [40, 0, 0, 0, 41, 0, 0, 0, 0, 0, 41.6, 0, 20;
     20, 0, 0, 0, 23, 0, 0, 0, 0, 0, 23, 0, 189;
     102, 0, 0, 0, 192, 0, 0, 0, 0, 0, 96, 0, 21];

The number of zeroes between two non-zero numbers in each row is random, but this number is always the same between rows. I want to interpolate each row like this:

Minter = [40, 40.25, 40.5, 40.75, 41, 41.1, 41.2, 41.3, 41.4, 41.5, 41.6, 30.8, 20;
          20, 20.75, 21.5, 22.25, 23, 23,   23,   23,   23,   23,   23,   106, 189;
          102, 124.5, 147, 169.5, 192, 176, 160,  144,  128,  112,  96,   58.5, 21];

So I want to replace the zeroes with numbers obtained with linear interpolation method.

I wrote my own function to do this. I'm using the MATLAB function find for searching for the indexes of numbers which are >0, and then depending on difference between two indexes (from the find function) and depending on the first right and left non-zero number (from the original matrix), I calculate numbers between these two non-zero numbers and replace zeroes with these numbers in the original matrix. I am working on each row separately.

This method work OK, but it is not very fast. Is any faster way in MATLAB? I tried the interp1 function, but without much success.

1

There are 1 answers

0
rayryeng On

Yes you can still use interp1, but you have to be clever about it. Taking note of the fact that you're interpolating each row of your matrix separately, we can use find and we can operate on the transpose of the matrix to find those column-major locations that are non-zero. This is important because we want to interpolate the matrix values per row and find works in column-major order. If you want to operate per row, you'll need to transpose the matrix to get the desired effect.

Once you're done, you can use these indices as well as those values in the transpose of the matrix that are non-empty as key points, then use lookup points that vary from 1 up to as many elements as we have in M to fill in those values in M that are zero. This will only give us a 1D array though, so we'll need to reshape the matrix and transpose back when we're done. The transpose is again important because reshape reshapes a vector in a column-major fashion, so this last step ensures that we get everything in row-major.

Do something like this:

%// Your matrix
M=[40, 0, 0, 0, 41, 0, 0, 0, 0, 0, 41.6, 0, 20;
20, 0, 0, 0, 23, 0, 0, 0, 0, 0, 23, 0, 189;
102, 0, 0, 0, 192, 0, 0, 0, 0, 0, 96, 0, 21];

%// New code
Mt = M.'; %// Transpose
ind = find(Mt); %// Find column-major indices
Minter = interp1(ind, Mt(ind), 1:numel(M)); %// Interpolate per row
Minter = reshape(Minter, size(M,2), size(M,1)).'; %// Reshape and transpose back

We get:

Minter =

  Columns 1 through 8

   40.0000   40.2500   40.5000   40.7500   41.0000   41.1000   41.2000   41.3000
   20.0000   20.7500   21.5000   22.2500   23.0000   23.0000   23.0000   23.0000
  102.0000  124.5000  147.0000  169.5000  192.0000  176.0000  160.0000  144.0000

  Columns 9 through 13

   41.4000   41.5000   41.6000   30.8000   20.0000
   23.0000   23.0000   23.0000  106.0000  189.0000
  128.0000  112.0000   96.0000   58.5000   21.0000

This agrees with your desired output.