Python

时间:2016-09-07 23:03:05

标签: python numpy interpolation

我在一个以pi弧度包裹的域上有角度数据(即0 = pi)。数据为2D,其中一维代表角度。我需要以包装的方式将这些数据插入另一个网格。

在一个维度中,np.interp函数需要一段时间kwarg(对于NumPy 1.10及更高版本): http://docs.scipy.org/doc/numpy/reference/generated/numpy.interp.html

这正是我所需要的,但我需要二维。我目前只是单步执行数组中的列并使用np.interp,但这当然很慢。

那里有什么可以实现同样的结果但更快?

1 个答案:

答案 0 :(得分:1)

np.interp如何运作的解释

使用source,Luke!

numpy doc for np.interp使得源代码特别容易找到,因为它在那里有链接以及文档。让我们逐行了解一下。

首先,回想一下参数:

"""
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])  # Peskiest points possible }:)
period = np.pi

现在,在所有类型检查发生后,我从源代码中的period != None分支开始:

# normalizing periodic boundaries
x = x % period
xp = xp % period

这只是确保所提供的xxp的所有值都在0period之间。因此,由于期间为pi,但我们指定xxp介于-pi/2pi/2之间,这将通过添加{{}来调整1}}到pi范围内的所有值,以便它们有效地出现在[-pi/2, 0)之后。因此,我们的pi/2现在会读取xp

[pi/2, 3*pi/4, 0, pi/4]

这只是按递增顺序排序asort_xp = np.argsort(xp) xp = xp[asort_xp] fp = fp[asort_xp] 。在上一步中执行模数运算后尤其需要这样做。所以,现在xpxp[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) # Paraphrasing a little 执行线性插值。在尝试在np.interp中的两个点ab之间进行插值时,它仅使用xpf(a)的值(即{的值} {1}}在相应的索引处)。那么f(b)在最后一步中所做的是取点fp并将其放在数组前面,取点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

现在,来看你的2D案例:

假设你有一个网格和一些值。让我们把所有的值都放在[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 # Put x on the 1st dim and y on the 2nd dim; f is linear in y fp = np.array([0, 1, 0, -1])[:, np.newaxis] + yp[np.newaxis, :] # >>> fp # array([[ 0, 1, 2, 3], # [ 1, 2, 3, 4], # [ 0, 1, 2, 3], # [-1, 0, 1, 2]]) ,调整时间段。请注意我是如何使用单例列表xp[[-1]]xp[[0]]编制索引的。这是trick,以确保dimensions are preserved

[-1]

最后,您可以自由使用scipy.interpolate.interpn来获得结果。让我们获得所有[0]的{​​{1}}值:

xp = np.concatenate((xp[[-1]]-period, xp, xp[[0]]+period))
fp = np.concatenate((fp[[-1], :], fp, fp[[0], :]))
必须将

x = pi/8指定为Nx2点的矩阵,其中第一个维度是您希望在第二个维度处插值的每个点,给出该点的x和y坐标。有关详细说明,请参阅this answer

如果您希望获得超出y范围的值,您需要自己对其进行模数化:

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)
# >>> result
# array([ 0.5,  1.5,  2.5,  3.5])

同样,如果您想为一堆x值和y值生成interp_points,请查看this answer