如何从大型(scipy.sparse)矩阵计算对角度矩阵?
给定一个一百万维的方阵,我想计算它的对角度矩阵。
对角度矩阵是一个对角矩阵,它的每个元素表示每一行中非零值的数量。
这个矩阵我们称为 A
,它的格式是 scipy.sparse.csr_matrix
。
如果我的机器性能足够强,我会直接这样做:
diagonal_degrees = []
for row in A:
diagonal_degrees.append(numpy.sum(row!=0))
我确实尝试过这样做,但结果是一个
ValueError: array is too big.
所以我尝试利用 scipy 的稀疏结构。我想到了这种方法:
diagonal_degrees = []
CSC_format = A.tocsc() # A is in scipys CSR format.
for i in range(CSC_format.shape[0]):
row = CSC_format.getrow(i)
diagonal_degrees.append(numpy.sum(row!=0))
我有两个问题:
- 有没有更有效的方法,我可能忽略了?
- 虽然 scipy sparse 的文档 说:
在 CSR、CSC 和 COO 格式之间的所有转换都是高效的线性时间操作。
为什么在从 CSR 转换到 CSC 时我会得到一个
SparseEfficiencyWarning: changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.
?
1 个回答
4
如果你只需要计算非零元素的数量,可以使用一个叫做 nonzero
的方法,这个方法会很有用。
具体的代码示例是这样的(感谢 Joe Kington 和 matehat 的帮助):
diag_deg, _ = np.histogram(x.nonzero()[0], np.arange(x.shape[0]+1))
# generating a diagonal matrix with diag_deg
dim = x.shape[0]
diag_mat = np.zeros((dim**2, ))
diag_mat[np.arange(0, dim**2, dim+1)] = diag_deg
diag_mat.reshape((dim, dim))
不过,对于很大的数组(比如说 dim ~ 1 million
),正如 Aufwind 提到的,使用 np.zeros((dim**2, ))
会出现一个错误:ValueError: Maximum allowed dimension exceeded
。一种替代的解决方法是使用稀疏矩阵:
diag_mat = sparse.coo_matrix((dim, dim))
diag_mat.setdiag(diag_deg)