np.interp
的工作原理解释
使用源代码,Luke!
np.interp
的numpy文档使得在文档中查找源代码变得特别容易,因为它直接提供了链接和文档。让我们逐行分析这个函数。
首先,回忆一下参数:
"""
x : array_like
The x-coordinates of the interpolated values.
xp : 1-D sequence of floats
The x-coordinates of the data points, must be increasing if argument
`period` is not specified. Otherwise, `xp` is internally sorted after
normalizing the periodic boundaries with ``xp = xp % period``.
fp : 1-D sequence of floats
The y-coordinates of the data points, same length as `xp`.
period : None or float, optional
A period for the x-coordinates. This parameter allows the proper
interpolation of angular x-coordinates. Parameters `left` and `right`
are ignored if `period` is specified.
"""
在阅读本文时,让我们以三角波为例进行简单说明:
xp = np.array([-np.pi/2, -np.pi/4, 0, np.pi/4])
fp = np.array([0, -1, 0, 1])
x = np.array([-np.pi/8, -5*np.pi/8])
period = np.pi
现在,在所有类型检查之后,我从源代码的
period != None
分支开始:
x = x % period
xp = xp % period
这只是确保提供的所有x
和xp
值都在0
到period
之间。因此,由于周期为pi
,但我们指定x
和xp
在-pi/2
和pi/2
之间,这将通过将[-pi/2, 0)
范围内的所有值加上pi
来进行调整,以便它们实际上出现在pi/2
之后。因此,我们的xp
现在变为[pi/2, 3*pi/4, 0, pi/4]
。
asort_xp = np.argsort(xp)
xp = xp[asort_xp]
fp = fp[asort_xp]
这只是按递增顺序排序
xp
的过程。在执行前一步骤中的模运算后,特别需要进行此操作。因此,现在
xp
为
[0,pi/4,pi/2,3 * pi / 4]
。
fp
也相应地被洗牌,
[0,1,0,-1]
。
xp = np.concatenate((xp[-1:]-period, xp, xp[0:1]+period))
fp = np.concatenate((fp[-1:], fp, fp[0:1]))
return compiled_interp(x, xp, fp, left, right)
np.interp
执行线性插值。当尝试在 xp
中寻找两个点 a
和 b
之间的插值时,它仅使用相应索引处的 fp
值,即 f(a)
和 f(b)
的值。因此,np.interp
在最后一步所做的是将点 xp[-1]
放在数组前面,并将点 xp[0]
放在数组后面,但分别减去和加上一个周期。因此,您现在有一个新的 xp
,看起来像这样:[-pi/4, 0, pi/4, pi/2, 3*pi/4, pi]
。同样,fp[0]
和 fp[-1]
已经连接在一起,因此 fp
现在为 [-1, 0, 1, 0, -1, 0]
。
请注意,在模运算之后,
x
也已经被带入了
[0, pi]
范围内,因此
x
现在是
[7*pi/8, 3*pi/8]
。这让你很容易地看出你将得到
[-0.5, 0.5]
。
现在,针对你的二维情况:
假设你有一个网格和一些数值。让我们先把所有的数值都限制在[0, pi]
之间,这样我们就不需要担心取模和混淆了。
xp = np.array([0, np.pi/4, np.pi/2, 3*np.pi/4])
yp = np.array([0, 1, 2, 3])
period = np.pi
fp = np.array([0, 1, 0, -1])[:, np.newaxis] + yp[np.newaxis, :]
我们现在知道,你只需要在数组前面添加
xp[[-1]]
,在末尾添加
xp[[0]]
,并调整周期即可。请注意,我使用了单例列表
[-1]
和
[0]
进行索引。这是一个
技巧,可以确保
维度被保留。
xp = np.concatenate((xp[[-1]]-period, xp, xp[[0]]+period))
fp = np.concatenate((fp[[-1], :], fp, fp[[0], :]))
最后,您可以自由使用
scipy.interpolate.interpn
来实现您的结果。让我们获取所有
y
在
x = pi/8
处的值:
from scipy.interpolate import interpn
interp_points = np.hstack(( (np.pi/8 * np.ones(4))[:, np.newaxis], yp[:, np.newaxis] ))
result = interpn((xp, yp), fp, interp_points)
interp_points
必须指定为一个Nx2的点矩阵,其中第一维表示您想要插值的每个点,第二维给出该点的x和y坐标。有关详细说明,请参见
this answer。
如果您想获得范围
[0, period]
之外的值,则需要自行进行模数运算:
x = 21 * np.pi / 8
x_equiv = x % period
interp_points = np.hstack(( (x_equiv * np.ones(4))[:, np.newaxis], yp[:, np.newaxis] ))
result = interpn((xp, yp), fp, interp_points)
如果您想为一堆x和y值生成interp_points
,请参考这个答案。
scipy.interpolate.interp2d
吗? - James