在 scipy.sparse 矩阵中访问 row/column 中的非零值的最有效方法
Most efficient way of accessing non-zero values in row/column in scipy.sparse matrix
访问 scipy.sparse
矩阵 scipy.sparse
行 row
或列 col
中所有非零值的最快方式或最不冗长的方式是什么 A
CSR
格式?
换一种格式(比如,COO
)会不会更有效率?
现在,我使用以下内容:
A[row, A[row, :].nonzero()[1]]
或
A[A[:, col].nonzero()[0], col]
对于这样的问题,了解不同格式的底层数据结构是值得的:
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
和 returns row
和 col
属性(或多或少 - 查看其代码)。
为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()
不添加任何内容。
直接访问 csr
和 lil
的属性在选择列时不是很好。因为 csc
更好,或者 lil
转置。
在 indptr
的帮助下直接访问 csr
data
将是:
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
,获取每一行的值 - 但它们在编译代码中执行此操作。
最近的一个相关话题,按行求非零元素的乘积:
我发现 reduceat
使用 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
这种乘法。如果我没记错的话,它实际上是这样执行的 A[0,:]
访问 scipy.sparse
矩阵 scipy.sparse
行 row
或列 col
中所有非零值的最快方式或最不冗长的方式是什么 A
CSR
格式?
换一种格式(比如,COO
)会不会更有效率?
现在,我使用以下内容:
A[row, A[row, :].nonzero()[1]]
或
A[A[:, col].nonzero()[0], col]
对于这样的问题,了解不同格式的底层数据结构是值得的:
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
和 returns row
和 col
属性(或多或少 - 查看其代码)。
为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()
不添加任何内容。
直接访问 csr
和 lil
的属性在选择列时不是很好。因为 csc
更好,或者 lil
转置。
在 indptr
的帮助下直接访问 csr
data
将是:
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
,获取每一行的值 - 但它们在编译代码中执行此操作。
最近的一个相关话题,按行求非零元素的乘积:
我发现 reduceat
使用 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
这种乘法。如果我没记错的话,它实际上是这样执行的 A[0,:]