2d数组中索引对之间的和

use*_*752 10 python numpy sum multidimensional-array

对不起,如果没有得到答案,我不知道重新提问的协议.几个月前在这里提出这个问题:2d数组中的指数对之间的Numpy和

我有一个2-d numpy数组(MxN)和另外两个1-d数组(Mx1),它们代表我想要总结的2-d数组的每一行的起始和结束索引.我正在寻找在大型阵列中执行此操作的最有效方法(最好不必使用循环,这是我目前正在做的事情).我想做的一个例子如下.

>>> random.seed(1234)
>>> a = random.rand(4,4)
>>> print a
[[ 0.19151945  0.62210877  0.43772774  0.78535858]
 [ 0.77997581  0.27259261  0.27646426  0.80187218]
 [ 0.95813935  0.87593263  0.35781727  0.50099513]
 [ 0.68346294  0.71270203  0.37025075  0.56119619]]
>>> b = array([1,0,2,1])
>>> c = array([3,2,4,4])
>>> d = empty(4)
>>> for i in xrange(4):
    d[i] = sum(a[i, b[i]:c[i]]) 

>>> print d
[ 1.05983651  1.05256841  0.8588124   1.64414897]
Run Code Online (Sandbox Code Playgroud)

我的问题类似于以下问题,但是,我不认为那里提出的解决方案会非常有效.在索引对之间的子阵列中的Numpy值的总和在该问题中,他们想要找到同一行的多个子集的总和,因此cumsum()可以使用.但是,我只会在每行中找到一个总和,所以我认为这不是计算总和的最有效方法.

Jai*_*ime 11

EDIT为目前为止所有答案添加了时序结果,包括以下@ seberg评论后的OP代码,OP的方法最快:

def sliced_sum_op(a, b, c) :
    d = np.empty(a.shape[0])
    for i in xrange(a.shape[0]):
        d[i] = np.sum(a[i, b[i]:c[i]]) 
    return d
Run Code Online (Sandbox Code Playgroud)

您仍然可以通过np.cumsum 大幅提升来完成它,尽管它需要的存储空间相当于原始数组的大小:

def sliced_sum(a, b, c) :
    cum = np.cumsum(a, axis=1)
    cum = np.hstack((np.zeros((a.shape[0], 1), dtype=a.dtype), cum))
    rows = np.arange(a.shape[0])
    return cum[rows, c] - cum[rows, b]
Run Code Online (Sandbox Code Playgroud)

计时对你的数组具有欺骗性,因为对于小数组大小,你的方法实际上比这个方法略快.但numpy很快就会赢得它,请参阅下面的图表,了解随机方形阵列的大小(n, n):

在此输入图像描述

上面的内容是用

import timeit
import matplotlib.pyplot as plt

n = np.arange(10, 1000, 10)
op = np.zeros(n.shape[0])
me = np.zeros(n.shape[0])
th = np.zeros(n.shape[0])
jp = np.zeros(n.shape[0])
for j, size in enumerate(n) :
    a = np.random.rand(size, size)
    b, c = indices = np.sort(np.random.randint(size + 1,
                                               size=(2, size)), axis=0)
    np.testing.assert_almost_equal(sliced_sum_op(a, b, c),
                                   sliced_sum(a, b, c))
    np.testing.assert_almost_equal(sliced_sum_op(a, b, c),
                                   sum_between2(a, b, c))
    np.testing.assert_almost_equal(sliced_sum_op(a, b, c),
                                   sum_between_mmult(a, b, c))

    op[j] = timeit.timeit('sliced_sum_op(a, b, c)',
                          'from __main__ import sliced_sum_op, a, b, c',
                          number=10)
    me[j] = timeit.timeit('sliced_sum(a, b, c)',
                          'from __main__ import sliced_sum, a, b, c',
                          number=10)
    th[j] = timeit.timeit('sum_between2(a, b, c)',
                          'from __main__ import sum_between2, a, b, c',
                          number=10)
    jp[j] = timeit.timeit('sum_between_mmult(a, b, c)',
                          'from __main__ import sum_between_mmult, a, b, c',
                          number=10)
plt.subplot(211)
plt.plot(n, op, label='op')
plt.plot(n, me, label='jaime')
plt.plot(n, th, label='thorsten')
plt.plot(n, jp, label='japreiss')
plt.xlabel('n')
plt.legend(loc='best')
plt.show()
Run Code Online (Sandbox Code Playgroud)