編集以下の@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
元のアレイのサイズと同等のストレージが必要になりますが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]
配列のサイズが小さい場合、メソッドは実際にはこれよりもわずかに高速であるため、タイミングは配列を欺くものです。しかし、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()