对 scipy.sparse.csr_matrix 中的行求和

Posted

技术标签:

【中文标题】对 scipy.sparse.csr_matrix 中的行求和【英文标题】:Sum over rows in scipy.sparse.csr_matrix 【发布时间】:2015-06-20 05:01:35 【问题描述】:

我有一个很大的 csr_matrix,我想添加多个行并获得一个具有相同列数但行数减少的新 csr_matrix。 (上下文:矩阵是从sklearn CountVectorizer得到的document-term矩阵,我希望能够根据这些文档关联的代码快速组合文档)

举个简单的例子,这是我的矩阵:

import numpy as np
from scipy.sparse import csr_matrix
from scipy.sparse import vstack

row = np.array([0, 4, 1, 3, 2])
col = np.array([0, 2, 2, 0, 1])
dat = np.array([1, 2, 3, 4, 5])
A = csr_matrix((dat, (row, col)), shape=(5, 5))
print A.toarray()

[[1 0 0 0 0]
 [0 0 3 0 0]
 [0 5 0 0 0]
 [4 0 0 0 0]
 [0 0 2 0 0]]

不,假设我想要一个新矩阵 B,其中行 (1, 4) 和 (2, 3, 5) 通过求和组合在一起,看起来像这样:

[[5 0 0 0 0]
 [0 5 5 0 0]]

并且应该再次采用稀疏格式(因为我正在使用的真实数据很大)。我试图对矩阵的切片求和,然后将其堆叠:

idx1 = [1, 4]
idx2 = [2, 3, 5]
A_sub1 = A[idx1, :].sum(axis=1)
A_sub2 = A[idx2, :].sum(axis=1)
B = vstack((A_sub1, A_sub2))

但这给了我切片中非零列的总和值,所以我不能将它与其他切片合并,因为求和切片中的列数不同。

我觉得必须有一个简单的方法来做到这一点。但我在网上或文档中找不到任何关于此的讨论。我错过了什么?

感谢您的帮助

【问题讨论】:

【参考方案1】:

请注意,您可以通过仔细构造另一个矩阵来做到这一点。以下是它对密集矩阵的工作方式:

>>> S = np.array([[1, 0, 0, 1, 0,], [0, 1, 1, 0, 1]])
>>> np.dot(S, A.toarray())
array([[5, 0, 0, 0, 0],
       [0, 5, 5, 0, 0]])
>>>

稀疏版本只是稍微复杂一点。 row

col = range(5)
row = [0, 1, 1, 0, 1]
dat = [1, 1, 1, 1, 1]
S = csr_matrix((dat, (row, col)), shape=(2, 5))
result = S * A
# check that the result is another sparse matrix
print type(result)
# check that the values are the ones we want
print result.toarray()

输出:

<class 'scipy.sparse.csr.csr_matrix'>
[[5 0 0 0 0]
 [0 5 5 0 0]]

您可以通过在row 中包含更高的值并相应地扩展S 的形状来处理输出中的更多行。

【讨论】:

您好,感谢您的回答。我无法将矩阵 A 转换为数组,因为它太大了。但我想我可以直接在稀疏矩阵上做矩阵相乘? 啊,最后一个 toarray 只是为了表明当我们在这个小例子中乘以 S * A 时我们得到了正确的答案——我并不是说你会转换成密集的代码中的数组。我会添加评论。【参考方案2】:

索引应该是:

idx1 = [0, 3]       # rows 1 and 4
idx2 = [1, 2, 4]    # rows 2,3 and 5

那么你需要保持A_sub1A_sub2为稀疏格式并使用axis=0

A_sub1 = csr_matrix(A[idx1, :].sum(axis=0))
A_sub2 = csr_matrix(A[idx2, :].sum(axis=0))
B = vstack((A_sub1, A_sub2))
B.toarray()
array([[5, 0, 0, 0, 0],
       [0, 5, 5, 0, 0]])

注意,我认为A[idx, :].sum(axis=0) 操作涉及从稀疏矩阵转换 - 所以@Mr_E 的答案可能更好。

或者,当您使用axis=0np.vstack(而不是scipy.sparse.vstack)时,它可以工作:

A_sub1 = A[idx1, :].sum(axis=0)
A_sub2 = A[idx2, :].sum(axis=0)
np.vstack((A_sub1, A_sub2))

给予:

matrix([[5, 0, 0, 0, 0],
        [0, 5, 5, 0, 0]])

【讨论】:

A.sum(0) 使用np.matrix(np.ones((1,5),int))*A,它返回一个密集矩阵。 sparse.csr_matrix(np.ones((1,5),int))*A 返回稀疏。

以上是关于对 scipy.sparse.csr_matrix 中的行求和的主要内容,如果未能解决你的问题,请参考以下文章

ndarray 与 scipy.sparse.csr.csr_matrix 的互转

以可移植数据格式保存/加载 scipy sparse csr_matrix

scipy csr_matrix和csc_matrix函数详解

如何从一个巨大的(scipy.sparse)矩阵计算对角矩阵?

从稀疏矩阵导入时出现 Modin AttributeError

python - dict.setdefault