Extrapolate with LinearNDInterpolator

后端 未结 3 1409
长情又很酷
长情又很酷 2021-01-03 13:55

I\'ve got a 3D dataset that I want to interpolate AND extrapolate linearly. The interpolation can be done easily with scipy.interpolate.LinearNDInterpolator. The module can

相关标签:
3条回答
  • 2021-01-03 14:21

    I propose a method, the code is awful but I hope it will help you. The idea is, if you know by advance the bounds in which you will have to extrapolate, you can add extra columns/rows at the edge of your arrays with linearly extrapolated values, and then interpolate on the new array. Here is an example with some data that will be extrapolated until x=+-50 and y=+-40:

    import numpy as np
    x,y=np.meshgrid(np.linspace(0,6,7),np.linspace(0,8,9)) # create x,y grid
    z=x**2*y # and z values
    # create larger versions with two more columns/rows
    xlarge=np.zeros((x.shape[0]+2,x.shape[1]+2))
    ylarge=np.zeros((x.shape[0]+2,x.shape[1]+2))
    zlarge=np.zeros((x.shape[0]+2,x.shape[1]+2))
    xlarge[1:-1,1:-1]=x # copy data on centre
    ylarge[1:-1,1:-1]=y
    zlarge[1:-1,1:-1]=z
    # fill extra columns/rows
    xmin,xmax=-50,50
    ymin,ymax=-40,40
    xlarge[:,0]=xmin;xlarge[:,-1]=xmax # fill first/last column
    xlarge[0,:]=xlarge[1,:];xlarge[-1,:]=xlarge[-2,:] # copy first/last row
    ylarge[0,:]=ymin;ylarge[-1,:]=ymax
    ylarge[:,0]=ylarge[:,1];ylarge[:,-1]=ylarge[:,-2]
    # for speed gain: store factor of first/last column/row
    first_column_factor=(xlarge[:,0]-xlarge[:,1])/(xlarge[:,1]-xlarge[:,2]) 
    last_column_factor=(xlarge[:,-1]-xlarge[:,-2])/(xlarge[:,-2]-xlarge[:,-3])
    first_row_factor=(ylarge[0,:]-ylarge[1,:])/(ylarge[1,:]-ylarge[2,:])
    last_row_factor=(ylarge[-1,:]-ylarge[-2,:])/(ylarge[-2,:]-ylarge[-3,:])
    # extrapolate z; this operation only needs to be repeated when zlarge[1:-1,1:-1] is updated
    zlarge[:,0]=zlarge[:,1]+first_column_factor*(zlarge[:,1]-zlarge[:,2]) # extrapolate first column
    zlarge[:,-1]=zlarge[:,-2]+last_column_factor*(zlarge[:,-2]-zlarge[:,-3]) # extrapolate last column
    zlarge[0,:]=zlarge[1,:]+first_row_factor*(zlarge[1,:]-zlarge[2,:]) # extrapolate first row
    zlarge[-1,:]=zlarge[-2,:]+last_row_factor*(zlarge[-2,:]-zlarge[-3,:]) #extrapolate last row
    

    Then you can interpolate on (xlarge,ylarge,zlarge). Since all operations are numpy slices operations, I hope it will be fast enough for you. When z data are updated, copy them in zlarge[1:-1,1:-1] and re-execute the 4 last lines.

    0 讨论(0)
  • 2021-01-03 14:41

    use combination of nearest and linear interpolation. LinearNDInterpolator returns np.nan if it fails to interpolate otherwise it returns an array size(1) NearestNDInterpolator returns a float

    import scipy.interpolate
    import numpy
    class LinearNDInterpolatorExt(object):
      def __init__(self, points,values):
        self.funcinterp=scipy.interpolate.LinearNDInterpolator(points,values)
        self.funcnearest=scipy.interpolate.NearestNDInterpolator(points,values)
      def __call__(self,*args):
        t=self.funcinterp(*args)
        if not numpy.isnan(t):
          return t.item(0)
        else:
          return self.funcnearest(*args)
    
    0 讨论(0)
  • 2021-01-03 14:41

    I modified @Keith Williams answer slightly, which worked well for me (noting it does not extrapolate linearly - it only uses nearest neighbour):

    import numpy as np
    from scipy.interpolate import LinearNDInterpolator as linterp
    from scipy.interpolate import NearestNDInterpolator as nearest
    
    class LinearNDInterpolatorExt(object):
        def __init__(self, points, values):
            self.funcinterp = linterp(points, values)
            self.funcnearest = nearest(points, values)
        
        def __call__(self, *args):
            z = self.funcinterp(*args)
            chk = np.isnan(z)
            if chk.any():
                return np.where(chk, self.funcnearest(*args), z)
            else:
                return z
    
    0 讨论(0)
提交回复
热议问题