假设我有两个矩阵M和N(它们都有>1列)。 我还有一个索引矩阵I,其中包括2列--一列是针对M的,另一列是针对N的。 N的索引是唯一的,但M的索引可能会出现多次。 我想执行的操作是
for i,j in w:
M[i] += N[j]
除了使用for循环,是否有更有效的方式来完成这个任务?
为了完整性,在 numpy >= 1.8 中,您还可以使用 np.add
的 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
除了明显的性能劣势外,它还有一些优点:
np.bincount
将其权重转换为双精度浮点数,而 .at
会使用数组的本机类型进行操作。 这使它成为处理复杂数字等问题的最简单选项。np.bincount
仅将权重相加,您可以使用所有 ufunc 的 at
方法,因此您可以反复执行 multiply
、logical_and
或其他您想要的操作。但对于您的用例,np.bincount
可能是最佳选择。
m
和n
而不是矩阵,因此在这个示例中np.bincount
可以工作但在我的用例中不能。另一方面,np.add.at
正好符合我的需求。谢谢! - duckworthd同时使用 m_ind,n_ind = w.T
,然后只需执行 M += np.bincount(m_ind, weights=N[n_ind], minlength=len(M))
bincount
可以解决这个问题,但我无法找到规律。 - Fred Foo>>> 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
进行分组。(实际上,除了m_ind
之外还有n_ind
这一事实与问题无关; 您可以设置N = N[n_ind]
。) 这里恰好有一个SciPy类可以完成此操作: scipy.sparse.csr_matrix
。
数据示例:
>>> 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()
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])
m_ind, n_ind = w.T; N = N[n_ind]; update = csr_matrix((N, m_ind, [0, len(N)])).toarray(); M[np.unique(m_ind)] += update.ravel()
。 - Fred FooM[np.unique(m_ind)] += update
部分得到了ValueError: non-broadcastable output operand with shape (1,) doesn't match the broadcast shape (1,1)
。只是错过了ravel
,没关系。 - Veedrac
M[w[:, 0]] += N[w[:, 1]]
会失败,因为w[:, 0]
中的索引不是唯一的,所以值会被覆盖。 - Fred FooI[i] = M[w[i,0]] + N[w[i,1]]
。那么,如何按w[:,0]
分组并对其值求和? - duckworthd