numpy:用索引数组有效求和

时间:2014-05-28 07:56:15

标签: python numpy

假设我有2个矩阵M和N(两个都有> 1列)。我还有一个索引矩阵I,有2列 - 1表示M,1表示N.N的索引是唯一的,但M的索引可能出现不止一次。我想要执行的操作是,

for i,j in w:
  M[i] += N[j]

除了for循环之外,还有更有效的方法吗?

3 个答案:

答案 0 :(得分:12)

为了完整性,在numpy> = 1.8中,您还可以使用np.add' s at方法:

In [8]: m, n = np.random.rand(2, 10)

In [9]: m_idx, n_idx = np.random.randint(10, size=(2, 20))

In [10]: m0 = m.copy()

In [11]: np.add.at(m, m_idx, n[n_idx])

In [13]: m0 += np.bincount(m_idx, weights=n[n_idx], minlength=len(m))

In [14]: np.allclose(m, m0)
Out[14]: True

In [15]: %timeit np.add.at(m, m_idx, n[n_idx])
100000 loops, best of 3: 9.49 us per loop

In [16]: %timeit np.bincount(m_idx, weights=n[n_idx], minlength=len(m))
1000000 loops, best of 3: 1.54 us per loop

除了明显的性能劣势之外,它还有一些优势:

  1. np.bincount将其权重转换为双精度浮点数,.at将与数组的本机类型一起运行。这使得它成为处理例如最简单的选择。数字复杂。
  2. np.bincount只会将权重加在一起,您对所有ufunc都有一个at方法,因此您可以重复multiply,或logical_and,或者您想要的任何内容。< / LI>

    但是对于您的用例,np.bincount可能是要走的路。

答案 1 :(得分:3)

同时使用m_ind, n_ind = w.T,只需执行M += np.bincount(m_ind, weights=N[n_ind], minlength=len(M))

答案 2 :(得分:1)

为清楚起见,我们来定义

>>> m_ind, n_ind = w.T

然后是for循环

for i, j in zip(m_ind, n_ind):
    M[i] += N[j]

更新条目M[np.unique(m_ind)]。写入的值为N[n_ind],必须按m_ind分组。 (除了n_ind之外还有m_ind这个问题实际上与问题相关;您可以设置N = N[n_ind]。)恰好有一个SciPy类正是这样做的:{ {3}}

示例数据:

>>> m_ind, n_ind = array([[0, 0, 1, 1], [2, 3, 0, 1]])
>>> M = np.arange(2, 6)
>>> N = np.logspace(2, 5, 4)

for循环的结果是M变为[110002 1103 4 5]。我们得到与csr_matrix相同的结果,如下所示。正如我之前所说,n_ind是不相关的,所以我们先摆脱它。

>>> N = N[n_ind]
>>> from scipy.sparse import csr_matrix
>>> update = csr_matrix((N, m_ind, [0, len(N)])).toarray()

CSR构造函数在所需索引处构建一个具有所需值的矩阵;其参数的第三部分是压缩列索引,这意味着值N[0:len(N)]具有索引m_ind[0:len(N)]。重复项总结:

>>> update
array([[ 110000.,    1100.]])

这具有(1, len(np.unique(m_ind)))形状,可以直接添加:

>>> M[np.unique(m_ind)] += update.ravel()
>>> M
array([110002,   1103,      4,      5])