在scipy.sparse矩阵中访问行/列中非零值的最有效方法

时间:2016-12-05 22:28:36

标签: python scipy sparse-matrix

访问row矩阵col的行scipy.sparse或列A中所有非零值的最快或最不用的方法是什么?以CSR格式?

以另一种格式(比如COO)更有效率吗?

现在,我使用以下内容:

A[row, A[row, :].nonzero()[1]]

A[A[:, col].nonzero()[0], col]

1 个答案:

答案 0 :(得分:5)

对于这样的问题,需要了解不同格式的基础数据结构:

In [672]: A=sparse.csr_matrix(np.arange(24).reshape(4,6))
In [673]: A.data
Out[673]: 
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
       18, 19, 20, 21, 22, 23], dtype=int32)
In [674]: A.indices
Out[674]: array([1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5], dtype=int32)
In [675]: A.indptr
Out[675]: array([ 0,  5, 11, 17, 23], dtype=int32)

行的data值是A.data内的切片,但识别该切片需要了解A.indptr(见下文)

coo

In [676]: Ac=A.tocoo()
In [677]: Ac.data
Out[677]: 
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
       18, 19, 20, 21, 22, 23], dtype=int32)
In [678]: Ac.row
Out[678]: array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3], dtype=int32)
In [679]: Ac.col
Out[679]: array([1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5], dtype=int32)

请注意,A.nonzeros()会转换为coo并返回rowcol属性(或多或少 - 查看其代码)。

对于lil格式;数据按行存储在列表中:

In [680]: Al=A.tolil()
In [681]: Al.data
Out[681]: 
array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23]], dtype=object)
In [682]: Al.rows
Out[682]: 
array([[1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5],
       [0, 1, 2, 3, 4, 5]], dtype=object)

===============

选择一行A可行,但根据我的经验往往有点慢,部分原因是它必须创建一个新的csr矩阵。你的表达似乎比需要的更啰嗦。

看着我的第一行有一个0元素(其他元素太密集):

In [691]: A[0, A[0,:].nonzero()[1]].A
Out[691]: array([[1, 2, 3, 4, 5]], dtype=int32)

整行表示为密集阵列:

In [692]: A[0,:].A
Out[692]: array([[0, 1, 2, 3, 4, 5]], dtype=int32)

但该行的data属性与您的选择相同

In [693]: A[0,:].data
Out[693]: array([1, 2, 3, 4, 5], dtype=int32)

并使用lil格式

In [694]: Al.data[0]
Out[694]: [1, 2, 3, 4, 5]

A[0,:].tocoo()无法添加任何内容。

在选择列时,直接访问csrlil的属性并不是很好。因为csc更好,或转置的lil

借助csr直接访问data indptr,将是:

In [697]: i=0; A.data[A.indptr[i]:A.indptr[i+1]]
Out[697]: array([1, 2, 3, 4, 5], dtype=int32)

使用csr格式的计算通常会像这样迭代indptr,获取每行的值 - 但是他们在编译的代码中执行此操作。

最近一个相关主题,逐行寻找非零元素的产品: Multiplying column elements of sparse Matrix

我发现使用reduceat的{​​{1}}非常快。

处理稀疏矩阵时的另一个工具是乘法

indptr

In [708]: (sparse.csr_matrix(np.array([1,0,0,0])[None,:])*A) Out[708]: <1x6 sparse matrix of type '<class 'numpy.int32'>' with 5 stored elements in Compressed Sparse Row format> 实际上通过这种乘法实现了csr。如果我的记忆是正确的,它实际上以这种方式执行sum

Sparse matrix slicing using list of int