将一个numpy数组插值以适应另一个数组

13

假设我有一个形状为(1, n)some_data数据。我有一个新的形状为(1, n±x)incoming_data数据,其中x是比n小得多的正整数。我想将incoming_data压缩或拉伸,使其与n具有相同的长度。使用SciPy堆栈,应该如何完成这个操作呢?

这里是我试图实现的一个例子。

# Stretch arr2 to arr1's shape while "filling in" interpolated value
arr1 = np.array([1, 5, 2, 3, 7, 2, 1])
arr2 = np.array([1, 5, 2, 3, 7, 1])
result
> np.array([1, 5, 2, 3, 6.x, 2.x 1])  # of shape (arr1.shape)

作为另一个例子:

# Squeeze arr2 to arr1's shape while placing interpolated value.
arr1 = np.array([1, 5, 2, 3, 7, 2, 1])
arr2 = np.array([1, 5, 2, 3, 4, 7, 2, 1])
result
> np.array([1, 5, 2, 3.x, 7.x, 2.x, 1])  # of shape (arr1.shape)

就我所知,我已经尝试使用 scipy.interpolate,但是我认为我错过了一些东西,无法正确完成插值,因为我不断收到错误消息,指出数组长度不同。 - ericmjl
1
使用interpolate,将x=np.arange(arr2.size)arr2作为基础点,插值到由np.linspace(0,arr2.size-1,arr1.size)给出的新x值。这些元素应该是您插值得到的数值。 - Andras Deak -- Слава Україні
请查看其手册。尝试使用help(scipy.interpolate.interp1d)在线文档 - Andras Deak -- Слава Україні
好的,明白了 - 所以使用您的解决方案,我最终需要跟踪哪个数组更长...除非我做错了什么?(我很确定我做错了什么...)我有一个向量,它是参考长度(在上面的示例中,它是 arr1),我想将所有内容插值为参考长度。 - ericmjl
我是新手,请忽略我的先前评论。我将在下面发布我的答案,并感谢您的帮助,@AndrasDeak! - ericmjl
显示剩余4条评论
2个回答

24
你可以使用 scipy.interpolate.interp1d 来实现数据的简单压缩或拉伸。我并不是说这一定有意义(选择何种插值方法很重要,你只有在正确猜测底层函数行为的情况下才能得到合理的结果),但你可以这样做。
其思路是将原始数组插值到其索引上作为 x 值,然后在一个更稀疏的 x 网格上进行插值,同时保持其端点不变。因此,你必须对离散数据进行连续性近似,并在必要的点上重新采样:
import numpy as np
import scipy.interpolate as interp
import matplotlib.pyplot as plt

arr_ref = np.array([1, 5, 2, 3, 7, 1])  # shape (6,), reference
arr1 = np.array([1, 5, 2, 3, 7, 2, 1])  # shape (7,), to "compress"
arr2 = np.array([1, 5, 2, 7, 1])        # shape (5,), to "stretch"
arr1_interp = interp.interp1d(np.arange(arr1.size),arr1)
arr1_compress = arr1_interp(np.linspace(0,arr1.size-1,arr_ref.size))
arr2_interp = interp.interp1d(np.arange(arr2.size),arr2)
arr2_stretch = arr2_interp(np.linspace(0,arr2.size-1,arr_ref.size))

# plot the examples, assuming same x_min, x_max for all data
xmin,xmax = 0,1
fig,(ax1,ax2) = plt.subplots(ncols=2)
ax1.plot(np.linspace(xmin,xmax,arr1.size),arr1,'bo-',
         np.linspace(xmin,xmax,arr1_compress.size),arr1_compress,'rs')
ax2.plot(np.linspace(xmin,xmax,arr2.size),arr2,'bo-',
         np.linspace(xmin,xmax,arr2_stretch.size),arr2_stretch,'rs') 
ax1.set_title('"compress"')
ax2.set_title('"stretch"')

最终的图表:

result

在这些图表中,蓝色圆圈是原始数据点,而红色正方形是插值得到的数据点(它们在边界处重叠)。正如您所见,我所说的压缩和拉伸实际上是基于底层(默认情况下为线性)函数的上采样和下采样。这就是为什么我说插值时必须非常小心:如果您的期望与数据不符,可能会得到非常错误的结果。


1
它完美运行,Andras!顺便提一句,我最终选择了Pchipinterpolator,因为它允许外推,在我的特定应用程序中,这正是我需要的。 - ericmjl
2
@ericmjl,我很高兴能够帮助:)感谢您的反馈。在从插值函数外推时要特别小心,这可能会导致无法控制的错误。(另外,为了完整起见:自scipy版本0.17起,interp1d支持线性插值的外推,关键字为full_value='extrapolate'。) - Andras Deak -- Слава Україні
还值得一提的是 resampy 包。如果你的数组是音频表示,那么该包比 scipy 更快地执行良好的插值。 - Jake Stevens-Haas
1
@JakeStevens-Haas 我对那个包完全不熟悉,但如果它能够实现问题所要求的功能,你应该考虑添加另一个答案。 - Andras Deak -- Слава Україні

7

还有一个非常适用于上采样和下采样的软件包: resampy。它比scipy.interpolate.interp1d命令更简单,但只使用一个插值函数。正如@Andras Deak所说,您在选择插值函数时必须小心。

MWE:

import numpy as np
import resampy
from matplotlib import pyplot as plt

x_mesh = np.linspace(0,1,10)
short_arr = np.sin(x_mesh*2*np.pi)
plt.plot(short_arr)

coarse_plot

interp_arr = resampy.resample(short_arr, 20, 100)
plt.plot(interp_arr)

fine_plot
两个注意事项:

  1. resampy使用“有限带宽sinc插值”。查看文档以获取更多信息。如果您的数组最初来自具有本地频率分量的数据,例如声音、图像和其他时间序列数据,则此方法效果最佳。在一些用于音频的tensorflow示例中使用了它,这也是我使用的。我不确定您的示例数组是否仅用于演示目的,但如果确实是您的数组大小,则无论您使用线性、样条还是其他任何方法,插值都可能是不好的。

  2. 您的示例展示了不仅仅是插值。似乎您找到了与之匹配的数组部分(例如[1,5,2,3]),然后对其余部分进行了插值。根据您要匹配数组开头还是任意数量的补丁,您可能需要使用两种方法:一种用于识别要插值的数组的正确部分,另一种用于插值这些部分。如果是这种情况,请查看numpy.isin以获取基本方法,或查看Levenshtein距离,以更一般地匹配一组子字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接