如何对numpy数组进行抽样,并高效地对每个样本进行计算?

4
假设我有一个一维数组,我想用移动窗口进行采样,在窗口内将每个元素除以第一个元素。
例如,如果我有 [2, 5, 8, 9, 6] 和窗口大小为3,结果将是:
[[1, 2.5, 4],
 [1, 1.6, 1.8],
 [1, 1.125, 0.75]].

我现在做的基本上是一个for循环。
import numpy as np
arr = np.array([2., 5., 8., 9., 6.])
window_size = 3
for i in range(len(arr) - window_size + 1):
  result.append(arr[i : i + window_size] / arr[i])

当数组很大时,它会变得非常慢,我想知道是否有更好的方法?我猜想无法避免O(n^2)的复杂度,但是NumPy可能有一些我不知道的优化。


您发布的代码并未产生您发布的结果。另外,请添加变量的初始化。 - Khris
也许使用一个不会导致对称矩阵的例子会更好,因为这会使得numpy广播更难理解。 - Khris
1个回答

5

这里是使用broadcasting的向量化方法 -

N = 3  # Window size
nrows = a.size-N+1
a2D = a[np.arange(nrows)[:,None] + np.arange(N)]
out = a2D/a[:nrows,None].astype(float)

我们也可以使用NumPy strides来更高效地提取滑动窗口,方法如下 -

n = a.strides[0]
a2D = np.lib.stride_tricks.as_strided(a,shape=(nrows,N),strides=(n,n))

样例运行 -

In [73]: a
Out[73]: array([4, 9, 3, 6, 5, 7, 2])

In [74]: N = 3
    ...: nrows = a.size-N+1
    ...: a2D = a[np.arange(nrows)[:,None] + np.arange(N)]
    ...: out = a2D/a[:nrows,None].astype(float)
    ...: 

In [75]: out
Out[75]: 
array([[ 1.        ,  2.25      ,  0.75      ],
       [ 1.        ,  0.33333333,  0.66666667],
       [ 1.        ,  2.        ,  1.66666667],
       [ 1.        ,  0.83333333,  1.16666667],
       [ 1.        ,  1.4       ,  0.4       ]])

你的解决方案在测试数组中给出了正确的结果,但在其他数组长度上失败,并显示“无法一起广播操作数”的错误。 - Khris
@Khris 感谢您指出,我的代码确实有一个错误。已经修复了。 - Divakar
我也在使用strides来解决问题。你的第二个strides解决方案比第一个快了两倍。我用长度为10000的数组计时了OP和你的两个算法。OP的时间是31.7毫秒,你的第一个算法用时740微秒,第二个算法用时378微秒。我的算法和你的第二个一样,所以我不会发表它。 - Khris
@Khris 感谢您的测试!很高兴看到 80x+ 的加速! - Divakar

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