在python中,将CSR向量添加到CSR矩阵的特定行的最佳方法是什么?我找到one workaround here,但想知道是否有更好/更有效的方法来做到这一点。非常感谢任何帮助。
给定NxM CSR矩阵 A 和1xM CSR矩阵 B ,以及行索引 i ,目标是添加 B 有效地 i 第< A 行。
答案 0 :(得分:1)
明显的索引添加确实有效。它提供了一个效率警告,但这并不意味着它是最慢的方式,只是你不应该反复这样做。它建议使用lil
格式,但转换为该格式并返回可能比执行csr
矩阵的添加需要更多时间。
In [1049]: B.A
Out[1049]:
array([[0, 9, 0, 0, 1, 0],
[2, 0, 5, 0, 0, 9],
[0, 2, 0, 0, 0, 0],
[2, 0, 0, 0, 0, 0],
[0, 9, 5, 3, 0, 7],
[1, 0, 0, 8, 9, 0]], dtype=int32)
In [1051]: B[1,:] += np.array([1,0,1,0,0,0])
/usr/local/lib/python3.5/dist-packages/scipy/sparse/compressed.py:730: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.
SparseEfficiencyWarning)
In [1052]: B
Out[1052]:
<6x6 sparse matrix of type '<class 'numpy.int32'>'
with 17 stored elements in Compressed Sparse Row format>
In [1053]: B.A
Out[1053]:
array([[0, 9, 0, 0, 1, 0],
[3, 0, 6, 0, 0, 9],
[0, 2, 0, 0, 0, 0],
[2, 0, 0, 0, 0, 0],
[0, 9, 5, 3, 0, 7],
[1, 0, 0, 8, 9, 0]])
如链接问题所示,可以直接对稀疏矩阵的属性进行操作。他的代码显示了为什么会出现效率警告 - 在一般情况下,它必须重建矩阵属性。
lil
对于行替换更有效,因为它只需更改矩阵.data
和.rows
属性中的子列表。一行中的更改不会更改任何其他行的属性。
也就是说,如果您的添加具有与原始行相同的稀疏性,则可以更改data
属性的特定元素,而无需重新处理.indices
或.indptr
。借鉴链接代码
A.data[:idx_start_row : idx_end_row]
是将被更改的A.data
切片。当然,您需要来自&#39;向量的相应切片。
从In [1049] B
In [1085]: B.indptr
Out[1085]: array([ 0, 2, 5, 6, 7, 11, 14], dtype=int32)
In [1086]: B.data
Out[1086]: array([9, 1, 2, 5, 9, 2, 2, 9, 5, 3, 7, 1, 8, 9], dtype=int32)
In [1087]: B.indptr[[1,2]] # row 1
Out[1087]: array([2, 5], dtype=int32)
In [1088]: B.data[2:5]
Out[1088]: array([2, 5, 9], dtype=int32)
In [1089]: B.indices[2:5] # row 1 column indices
Out[1089]: array([0, 2, 5], dtype=int32)
In [1090]: B.data[2:5] += np.array([1,2,3])
In [1091]: B.A
Out[1091]:
array([[ 0, 9, 0, 0, 1, 0],
[ 3, 0, 7, 0, 0, 12],
[ 0, 2, 0, 0, 0, 0],
[ 2, 0, 0, 0, 0, 0],
[ 0, 9, 5, 3, 0, 7],
[ 1, 0, 0, 8, 9, 0]], dtype=int32)
请注意更改后的值[3,7,12]采用lil
格式:
In [1092]: B.tolil().data
Out[1092]: array([[9, 1], [3, 7, 12], [2], [2], [9, 5, 3, 7], [1, 8, 9]], dtype=object)
答案 1 :(得分:0)
csr / csc矩阵对于大多数操作都是有效的,包括加法(O(nnz))。但是,几乎没有影响稀疏结构的更改(例如您的示例)甚至将单个位置从0切换为1都不是因为它们需要对表示进行O(nnz)重组。价值和指数是打包的;插入一个,以上都需要移动。
如果你只进行一次这样的操作,我的猜测就是你不能轻易击败scipy的实现。但是,如果您要添加多行,例如,首先制作它们的稀疏矩阵然后一次性添加它可能是值得的。
比如说,从行创建一个csr矩阵并不困难。例如,如果您的行是密集的并按顺序排列:
row_numbers, indices = np.where(rows)
data = rows[row_numbers, indices]
indptr = np.searchsorted(np.r_[true_row_numbers[row_numbers], N], np.arange(N+1))
如果您有一组稀疏行及其行号:
data = np.r_[tuple([r.data for r in rows])]
indices = np.r_[tuple(r.indices for r in rows])]
jumps = np.add.accumulate([0] + [len(r) for r in rows])
indptr = np.repeat(jumps, np.diff(np.r_[-1, true_row_numbers, N]))