6

Python 的 numpy 库对精美索引的“矢量化”有时会产生意想不到的结果。例如:

import numpy
a = numpy.zeros((1000,4), dtype='uint32')
b = numpy.zeros((1000,4), dtype='uint32')
i = numpy.random.random_integers(0,999,1000)
j = numpy.random.random_integers(0,3,1000)

a[i,j] += 1
for k in xrange(1000):
    b[i[k],j[k]] += 1

在数组 'a' 和 'b' 中给出不同的结果(即元组 (i,j) 的出现在 'a' 中显示为 1 而不管是否重复,而重复在 'b' 中计数)。这很容易验证如下:

numpy.sum(a)
883
numpy.sum(b)
1000

还值得注意的是,花哨的索引版本比 for 循环快两个数量级。我的问题是:“numpy 是否有一种有效的方法来计算重复计数,如在提供的示例中使用 for 循环实现的那样?”

4

1 回答 1

6

这应该做你想要的:

np.bincount(np.ravel_multi_index((i, j), (1000, 4)), minlength=4000).reshape(1000, 4)

作为细分,将和ravel_multi_index指定的索引对转换为整数索引到 C-flattened 数组;计算每个值出现在该索引列表中的次数;并将C-flattened 数组转换回 2d 数组。ijbincount0..4000reshape

在性能方面,我测量它比“b”快 200 倍,比“a”快 5 倍;你的旅费可能会改变。

由于您需要将计数写入现有数组a,请尝试以下操作:

u, inv = np.unique(np.ravel_multi_index((i, j), (1000, 4)), return_inverse=True)
a.flat[u] += np.bincount(inv)

我使第二种方法比“a”慢一点(2x),这并不奇怪,因为unique阶段会很慢。

于 2012-06-12T17:03:32.520 回答