scipy:将稀疏向量添加到稀疏矩阵的特定行

时间:2017-02-14 16:13:58

标签: numpy scipy

在python中,将CSR向量添加到CSR矩阵的特定行的最佳方法是什么?我找到one workaround here,但想知道是否有更好/更有效的方法来做到这一点。非常感谢任何帮助。

给定NxM CSR矩阵 A 和1xM CSR矩阵 B ,以及行索引 i ,目标是添加 B 有效地 i 第< A 行。

2 个答案:

答案 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]))