NumPy:如何计算多轴上的分段线性插值

NumPy:如何计算多轴上的分段线性插值,numpy,linear-interpolation,Numpy,Linear Interpolation,给定以下数据列t- In [26]: t.shape Out[26]: (3, 3, 2) In [27]: t Out[27]: array(

给定以下数据列
t
-

In [26]: t.shape                                                                                     
Out[26]: (3, 3, 2)

In [27]: t                                                                                           
Out[27]: 
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],

       [[ 6,  7],
        [ 8,  9],
        [10, 11]],

       [[12, 13],
        [14, 15],
        [16, 17]]])
t[:,0,0]
的分段线性插值可以使用以下公式计算
[0,0.666667,1.33333333,2.]
-

对于
fp
-

array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],

       [[ 4,  5],
        [ 6,  7],
        [ 8,  9]],

       [[ 8,  9],
        [10, 11],
        [12, 13]],

       [[12, 13],
        [14, 15],
        [16, 17]]])

您可以尝试
scipy.interpolate.interp1d

from scipy.interpolate import interp1d
import numpy as np

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

               [[ 6,  7],
                [ 8,  9],
                [10, 11]],

               [[12, 13],
                [14, 15],
                [16, 17]]])

# for the first slice
f = interp1d(np.arange(t.shape[0]), t[..., 0], axis=0)
# returns a function which you call with values within range np.arange(t.shape[0])

# data used for interpolation
t[..., 0]
>>> array([[ 0,  2,  4],
           [ 6,  8, 10],
           [12, 14, 16]])

f(1)
>>> array([ 6.,  8., 10.])

f(1.5)
>>> array([ 9., 11., 13.])

您可以尝试
scipy.interpolate.interp1d

from scipy.interpolate import interp1d
import numpy as np

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

               [[ 6,  7],
                [ 8,  9],
                [10, 11]],

               [[12, 13],
                [14, 15],
                [16, 17]]])

# for the first slice
f = interp1d(np.arange(t.shape[0]), t[..., 0], axis=0)
# returns a function which you call with values within range np.arange(t.shape[0])

# data used for interpolation
t[..., 0]
>>> array([[ 0,  2,  4],
           [ 6,  8, 10],
           [12, 14, 16]])

f(1)
>>> array([ 6.,  8., 10.])

f(1.5)
>>> array([ 9., 11., 13.])

由于插值是1d的,随着
y
值的变化,必须为t的每个1d切片运行插值。显式循环可能更快,但使用np.apply_沿_轴循环更整洁

import numpy as np

t = np.arange( 18 ).reshape(3,3,2)

x = np.linspace( 0, t.shape[0]-1, 4)
xp = np.arange(t.shape[0])


def interfunc( arr ):
    """ Function interpolates a 1d array. """
    return np.interp( x, xp, arr )

np.apply_along_axis( interfunc, 0, t ) # apply function along axis 0

"""  Result
array([[[ 0.,  1.],
        [ 2.,  3.],
        [ 4.,  5.]],

       [[ 4.,  5.],
        [ 6.,  7.],
        [ 8.,  9.]],

       [[ 8.,  9.],
        [10., 11.],
        [12., 13.]],

       [[12., 13.],
        [14., 15.],
        [16., 17.]]]) """
使用显式循环

result = np.zeros((4,3,2))
for c in range(t.shape[1]):
    for p in range(t.shape[2]):
       result[:,c,p] = np.interp( x, xp, t[:,c,p])
在我的机器上,第二个选项在一半的时间内运行

编辑以使用
np.nditer

由于结果和参数具有不同的形状,我似乎必须创建两个np.nditer对象,一个用于参数,一个用于结果。这是我第一次尝试将
nditer
用于任何可能过于复杂的事情

def test( t ):                                                              
    ts = t.shape              
    result = np.zeros((ts[0]+1,ts[1],ts[2]))
    param = np.nditer( [t], ['external_loop'], ['readonly'],  order = 'F')
    with np.nditer( [result], ['external_loop'], ['writeonly'],  order = 'F') as res:       
        for p, r in zip( param, res ):
            r[:] = interfunc(p)
    return result

它比显式循环稍慢,并且比其他任何一种解决方案都不容易遵循。

由于插值是1d,随着
y
值的变化,它必须针对t的每个1d切片运行。显式循环可能更快,但使用np.apply_沿_轴循环更整洁

import numpy as np

t = np.arange( 18 ).reshape(3,3,2)

x = np.linspace( 0, t.shape[0]-1, 4)
xp = np.arange(t.shape[0])


def interfunc( arr ):
    """ Function interpolates a 1d array. """
    return np.interp( x, xp, arr )

np.apply_along_axis( interfunc, 0, t ) # apply function along axis 0

"""  Result
array([[[ 0.,  1.],
        [ 2.,  3.],
        [ 4.,  5.]],

       [[ 4.,  5.],
        [ 6.,  7.],
        [ 8.,  9.]],

       [[ 8.,  9.],
        [10., 11.],
        [12., 13.]],

       [[12., 13.],
        [14., 15.],
        [16., 17.]]]) """
使用显式循环

result = np.zeros((4,3,2))
for c in range(t.shape[1]):
    for p in range(t.shape[2]):
       result[:,c,p] = np.interp( x, xp, t[:,c,p])
在我的机器上,第二个选项在一半的时间内运行

编辑以使用
np.nditer

由于结果和参数具有不同的形状,我似乎必须创建两个np.nditer对象,一个用于参数,一个用于结果。这是我第一次尝试将
nditer
用于任何可能过于复杂的事情

def test( t ):                                                              
    ts = t.shape              
    result = np.zeros((ts[0]+1,ts[1],ts[2]))
    param = np.nditer( [t], ['external_loop'], ['readonly'],  order = 'F')
    with np.nditer( [result], ['external_loop'], ['writeonly'],  order = 'F') as res:       
        for p, r in zip( param, res ):
            r[:] = interfunc(p)
    return result

它比显式循环稍慢,而且比其他任何一种解决方案都不容易遵循。

根据@Tis Chris的要求,这里有一个使用
np.nditer
multi_index
标志的解决方案,但我更喜欢显式嵌套
for
循环方法,因为它比上面的方法快10%

In [29]: t = np.arange( 18 ).reshape(3,3,2)                                                          

In [30]: ax0old = np.arange(t.shape[0])                                                              

In [31]: ax0new = np.linspace(0, t.shape[0]-1, 4)                                                    

In [32]: tnew = np.zeros((len(ax0new), t.shape[1], t.shape[2]))                                      

In [33]: it = np.nditer(t[0], flags=['multi_index'])                                                 

In [34]: for _ in it: 
    ...:     tnew[:, it.multi_index[0], it.multi_index[1]] = np.interp(ax0new, ax0old, t[:, it.multi_
    ...: index[0], it.multi_index[1]]) 
    ...:                                                                                             

In [35]: tnew                                                                                        
Out[35]: 
array([[[ 0.,  1.],
        [ 2.,  3.],
        [ 4.,  5.]],

       [[ 4.,  5.],
        [ 6.,  7.],
        [ 8.,  9.]],

       [[ 8.,  9.],
        [10., 11.],
        [12., 13.]],

       [[12., 13.],
        [14., 15.],
        [16., 17.]]])

根据@Tis Chris的要求,这里有一个使用
np.nditer
multi_index
标志的解决方案,但我更喜欢上面的显式嵌套
for
循环方法,因为它比以前快10%

In [29]: t = np.arange( 18 ).reshape(3,3,2)                                                          

In [30]: ax0old = np.arange(t.shape[0])                                                              

In [31]: ax0new = np.linspace(0, t.shape[0]-1, 4)                                                    

In [32]: tnew = np.zeros((len(ax0new), t.shape[1], t.shape[2]))                                      

In [33]: it = np.nditer(t[0], flags=['multi_index'])                                                 

In [34]: for _ in it: 
    ...:     tnew[:, it.multi_index[0], it.multi_index[1]] = np.interp(ax0new, ax0old, t[:, it.multi_
    ...: index[0], it.multi_index[1]]) 
    ...:                                                                                             

In [35]: tnew                                                                                        
Out[35]: 
array([[[ 0.,  1.],
        [ 2.,  3.],
        [ 4.,  5.]],

       [[ 4.,  5.],
        [ 6.,  7.],
        [ 8.,  9.]],

       [[ 8.,  9.],
        [10., 11.],
        [12., 13.]],

       [[12., 13.],
        [14., 15.],
        [16., 17.]]])

@我注意到您使用标准python循环技术来迭代
t
的第二和第三轴。使用
numpy.nditer
有什么好处吗?@user2309803我花了一些时间来试验
nditer
。由于文档的长度,我避免了它:-)这个解决方案似乎比其他任何一个都笨拙,但是对于这里的数据来说,运行速度比显式循环稍微慢一点。我不确定在这种情况下,
nditer
是否有任何好处。也许我的实现中遗漏了一些东西。@Tis Chris:我设法使用
np.nditer(t[0],flags=['multi_index'])重新实现了您的解决方案。
但是速度慢了10%。@user2309803:您能作为解决方案发布吗。我从来没有真正尝试过去理解nditer,也没有发现过我认为它能解决的问题。我注意到您使用标准的python循环技术在
t
的第二和第三轴上进行迭代。使用
numpy.nditer
有什么好处吗?@user2309803我花了一些时间来试验
nditer
。由于文档的长度,我避免了它:-)这个解决方案似乎比其他任何一个都笨拙,但是对于这里的数据来说,运行速度比显式循环稍微慢一点。我不确定在这种情况下,
nditer
是否有任何好处。也许我的实现中遗漏了一些东西。@Tis Chris:我设法使用
np.nditer(t[0],flags=['multi_index'])重新实现了您的解决方案。
但是速度慢了10%。@user2309803:您能作为解决方案发布吗。我从来没有真正尝试过去理解nditer,也没有发现过我认为它能解决的问题。很高兴见到你。谢谢。我现在更清楚这是怎么回事了。我有代码可以沿源数组的任意选定轴执行插值。我想知道nditer是否可以加快速度或让它更清晰,谢谢。我现在更清楚这是怎么回事了。我有代码可以沿源数组的任意选定轴执行插值。我想知道nditer能不能加快速度或者让它更清晰,