快速计算二维矩阵(数据向量列表)的滚动和

7

我正在寻找一种快速计算滚动和的方法,可能使用Numpy。这是我的第一种方法:

 def func1(M, w):
     Rtn = np.zeros((M.shape[0], M.shape[1]-w+1))
     for i in range(M.shape[1]-w+1):
         Rtn[:,i] = np.sum(M[:, i:w+i], axis=1)
     return Rtn

 M = np.array([[0.,  0.,  0.,  0.,  0.,  1.,  1.,  0.,  1.,  1.,  1.,  0.,  0.],
               [0.,  0.,  1.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.],
               [1.,  1.,  0.,  1.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.]])

 window_size = 4
 print func1(M, window_size)

 [[ 0.  0.  1.  2.  2.  3.  3.  3.  3.  2.]
  [ 1.  2.  2.  1.  1.  0.  0.  0.  1.  2.]
  [ 3.  2.  1.  1.  1.  1.  1.  1.  0.  0.]]

我希望能够防止窗口(/sum)在循环中被重复处理,并希望通过以下函数将其限制在滚动窗口的第一个和最后一个元素上,以期提高性能:

 def func2(M, w):
     output = np.zeros((M.shape[0], M.shape[1]-w+1))
     sum = np.sum(M[:, 0:w], axis=1)
     output[:,0] = sum

     for i in range(w, M.shape[1]):
         sum = sum + M[:,i]- M[:,i-w]
         output[:,i-w+1] = sum
     return output

但令我惊讶的是,func2 的速度几乎与 func1 相同:
 In [251]:
 M = np.random.randint(2, size=3000).reshape(3, 1000)

 window_size = 100
 %timeit func1(M, window_size)
 10 loops, best of 3: 20.9 ms per loop

 In [252]:
 %timeit func2(M, w)
 10 loops, best of 3: 15.5 ms per loop

我有所疑惑,你们知道更好、更快的方法来完成这个任务吗?


2
由于运行总和等于移动平均值,可能会出现重复:https://dev59.com/IWYq5IYBdhLWcg3wpyNE - Slater Victoroff
除了除法部分之外,其他都是可以的。 - YXD
1
你没有取实际的总和。你正在寻找一个滑动窗口,而不是一个累加和。 - smci
我认为仅使用滑动窗口也不正确。我认为你可以在滑动窗口(或滚动窗口)上进行求和或平均值。我建议将其编辑为滚动求和,这似乎更接近正确的做法。 - YXD
1
我同意E先生的观点,快速滚动求和是我想要的。很抱歉造成了混淆。 - user3329302
我更改了标题,以明确这个问题不是https://dev59.com/g2Yr5IYBdhLWcg3wYZKD的重复。 - Trevor Boyd Smith
1个回答

13

参考自@Jaime的答案,链接在这里: https://dev59.com/IWYq5IYBdhLWcg3wpyNE#14314054

import numpy as np

def rolling_sum(a, n=4) :
    ret = np.cumsum(a, axis=1, dtype=float)
    ret[:, n:] = ret[:, n:] - ret[:, :-n]
    return ret[:, n - 1:]

M = np.array([[0.,  0.,  0.,  0.,  0.,  1.,  1.,  0.,  1.,  1.,  1.,  0.,  0.],
              [0.,  0.,  1.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.],
              [1.,  1.,  0.,  1.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.]])

print(rolling_sum(M)) 

输出

[[ 0.  0.  1.  2.  2.  3.  3.  3.  3.  2.]
 [ 1.  2.  2.  1.  1.  0.  0.  0.  1.  2.]
 [ 3.  2.  1.  1.  1.  1.  1.  1.  0.  0.]]

计时

In [7]: %timeit rolling_sum(M, 4)
100000 loops, best of 3: 7.89 µs per loop

In [8]: %timeit func1(M, 4)
10000 loops, best of 3: 70.4 µs per loop

In [9]: %timeit func2(M, 4)
10000 loops, best of 3: 54.1 µs per loop

太棒了。只是有一个小问题,你必须取实际的 sum(running_sum(M)) - smci
你确定吗?我没有从问题中得到那个。 - YXD
在这种情况下,OP正在寻找一个滑动窗口,而不是一个运行总和。 - smci
1
是的,我认为你说得对,措辞不正确。但从问题中可以清楚地看出输出应该是什么。 - YXD
修正了标题和标签。 - smci

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