简体   繁体   中英

Interpolate 2D matrix along columns using Python

I am trying to interpolate a 2D numpy matrix with the dimensions (5, 3) to a matrix with the dimensions (7, 3) along the axis 1 (columns). Obviously, the wrong approach would be to randomly insert rows anywhere between the original matrix, see the following example:

Source:
 [[0, 1, 1]
  [0, 2, 0]
  [0, 3, 1]
  [0, 4, 0]
  [0, 5, 1]]

Target (terrible interpolation -> not wanted!):
 [[0, 1, 1]
  [0, 1.5, 0.5]
  [0, 2, 0]
  [0, 3, 1]
  [0, 3.5, 0.5]
  [0, 4, 0]
  [0, 5, 1]]

The correct approach would be to take every row into account and interpolate between all of them to expand the source matrix to a (7, 3) matrix. I am aware of the scipy.interpolate.interp1d or scipy.interpolate.interp2d methods, but could not get it to work with other Stack Overflow posts or websites. I hope to receive any type of tips or tricks.

Update #1: The expected values should be equally spaced.

Update #2: What I want to do is basically use the separate columns of the original matrix, expand the length of the column to 7 and interpolate between the values of the original column. See the following example:

Source:
 [[0, 1, 1]
  [0, 2, 0]
  [0, 3, 1]
  [0, 4, 0]
  [0, 5, 1]]

Split into 3 separate Columns:
 [0    [1    [1
  0     2     0
  0     3     1
  0     4     0
  0]    5]    1] 

Expand length to 7 and interpolate between them, example for second column:
 [1
  1.66
  2.33
  3
  3.66
  4.33
  5]   

It seems like each column can be treated completely independently, but for each column you need to define essentially an "x" coordinate so that you can fit some function "f(x)" from which you generate your output matrix. Unless the rows in your matrix are associated with some other datastructure (eg a vector of timestamps), an obvious set of x values is just the row-number:

x = numpy.arange(0, Source.shape[0])

You can then construct an interpolating function:

fit = scipy.interpolate.interp1d(x, Source, axis=0)

and use that to construct your output matrix:

Target = fit(numpy.linspace(0, Source.shape[0]-1, 7)

which produces:

array([[ 0.        ,  1.        ,  1.        ],
       [ 0.        ,  1.66666667,  0.33333333],
       [ 0.        ,  2.33333333,  0.33333333],
       [ 0.        ,  3.        ,  1.        ],
       [ 0.        ,  3.66666667,  0.33333333],
       [ 0.        ,  4.33333333,  0.33333333],
       [ 0.        ,  5.        ,  1.        ]])

By default, scipy.interpolate.interp1d uses piecewise-linear interpolation. There are many more exotic options within scipy.interpolate , based on higher order polynomials, etc. Interpolation is a big topic in itself, and unless the rows of your matrix have some particular properties (eg being regular samples of a signal with a known frequency range), there may be no "truly correct" way of interpolating. So, to some extent, the choice of interpolation scheme will be somewhat arbitrary.

You can do this as follows:

from scipy.interpolate import interp1d
import numpy as np


a = np.array([[0, 1, 1],
               [0, 2, 0],
               [0, 3, 1],
               [0, 4, 0],
               [0, 5, 1]])

x = np.array(range(a.shape[0]))

# define new x range, we need 7 equally spaced values
xnew = np.linspace(x.min(), x.max(), 7)

# apply the interpolation to each column
f = interp1d(x, a, axis=0)

# get final result
print(f(xnew))

This will print

[[ 0.          1.          1.        ]
 [ 0.          1.66666667  0.33333333]
 [ 0.          2.33333333  0.33333333]
 [ 0.          3.          1.        ]
 [ 0.          3.66666667  0.33333333]
 [ 0.          4.33333333  0.33333333]
 [ 0.          5.          1.        ]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM