Python 有效二维累积和

Python 有效二维累积和,python,arrays,numpy,scipy,cumsum,Python,Arrays,Numpy,Scipy,Cumsum,假设我有一个这样的数组 >>> a = np.arange(1,8).reshape((1,-1)) >>> a array([[1, 2, 3, 4, 5, 6, 7]]) 我想为a中的每个项目创建一个“接下来4个项目的总和”。也就是说,我的预期输出是 1, 2, 3, 4, 5, 6, 7, 8 1+2, 2+3, ... 1+2+3 2+3+4 ... 1+2+3+4 2+3+4+5 ... i、

假设我有一个这样的数组

>>> a = np.arange(1,8).reshape((1,-1))
>>> a
array([[1, 2, 3, 4, 5, 6, 7]])
我想为
a
中的每个项目创建一个“接下来4个项目的总和”。也就是说,我的预期输出是

1,       2,      3, 4, 5, 6, 7, 8
1+2,     2+3,     ...
1+2+3    2+3+4    ...
1+2+3+4  2+3+4+5  ...
i、 e.包含以下内容的矩阵:

1, 2, 3, 4, 5, 0, 0, 0
3, 5, 7, 9, 11,0, 0, 0
6, 9, 12,15,18,0, 0, 0
10,14,18,21,26,0, 0, 0
由于最后3项的累积和运算无法正确执行,因此我希望出现
0
。我知道如何做一个简单的算术运算。事实上,数组是

a[:4].cumsum().reshape((-1,1)); a[1:5].cumsum().reshape((-1,1))...

水平堆放。然而,我不知道如何有效地做到这一点。什么是很好的矢量化numpy方法?我也对
scipy
软件包持开放态度,只要它们在效率或可读性方面占主导地位。

一种可能的方法是使用滚动窗口方法结合
cumsum()

例如:

from numpy.lib.stride_tricks import as_strided

a = np.arange(1, 9) # the starting array
slice_length = 4
然后你可以写:

arr = as_strided(a, (slice_length, len(a)), (a.strides[0], a.strides[0])).cumsum(axis=0)
这可以让您在大部分情况下达到目的,但要填充剩余的
0
值,您可以使用slice和assign获得所需的输出:

arr[:, (1-slice_length):] = 0
那么您就有了数组:

>>> arr
array([[ 1,  2,  3,  4,  5,  0,  0,  0],
       [ 3,  5,  7,  9, 11,  0,  0,  0],
       [ 6,  9, 12, 15, 18,  0,  0,  0],
       [10, 14, 18, 22, 26,  0,  0,  0]])

我不知道是否有任何方法可以使用NumPy中的单个矢量化方法(即不使用切片)精确地生成所需的输出。(
acgregateat
,有点像
reduceeat
,添加到NumPy的UFUNC中可能是一件有趣的事情…

您可以使用一种更简单的称为“图像处理应用程序中的积分图像”的技术来高效地进行计算。首先计算并存储求和面积表,这是第一行的完整求和,前面添加了一个
0

a = np.arange(1, 8)
cs = np.concatenate(([0], np.cumsum(a)))
现在,您可以将每个“下一个
n
项的总和”创建为
cs[:n]-cs[:-n]

>>> for n in range(1, 5):
...     print n, '-->', (cs[n:] - cs[:-n])[:4]
...
1 --> [1 2 3 4]
2 --> [3 5 7 9]
3 --> [ 6  9 12 15]
4 --> [10 14 18 22]
你需要按照你想要的形状正确地排列它们,但是一旦原始计算完成,你就可以用一次减法来计算输出的每一项,这是最有效的方法。

你可以这样使用-

In [53]: a
Out[53]: array([ 4, 13,  4, 18,  1,  2, 11, 15])

In [54]: WSZ = 4 # Window size

In [55]: idx = np.arange(WSZ)[:,None] + np.arange(a.size-WSZ+1) # Broadcasted indices

In [56]: a[idx].cumsum(axis=0) # Index into "a" & perform cumsum along axis-0
Out[56]: 
array([[ 4, 13,  4, 18,  1],
       [17, 17, 22, 19,  3],
       [21, 35, 23, 21, 14],
       [39, 36, 25, 32, 29]], dtype=int32)
如果需要,用零填充-

In [57]: np.lib.pad(a[idx].cumsum(0),((0,0),(0,WSZ-1)),'constant',constant_values=0)
Out[57]: 
array([[ 4, 13,  4, 18,  1,  0,  0,  0],
       [17, 17, 22, 19,  3,  0,  0,  0],
       [21, 35, 23, 21, 14,  0,  0,  0],
       [39, 36, 25, 32, 29,  0,  0,  0]], dtype=int32)

现在,我更喜欢这个答案而不是另一个,因为我可以简单地进行其他计算,例如将
cumsum
更改为
cumprod
。但是,对于不同的起始数组,例如
a=np.ones((1,8))
,它似乎会崩溃。不确定发生了什么,需要先读取步幅。
步幅
只是NumPy必须在内存中跳转的字节数,以达到行或列中的下一个值。我的代码片段适用于1D输入-如果
a
是2D且只有一行,则需要将其更改为类似于
as_跨步(a,(切片长度,a.shape[1]),(a.strips[1],a.strips[1])。