制作样本:
In [51]: A=np.array([[1,2,0,0],[0,0,0,0],[2,0,3,0]])
In [52]: M=sparse.csr_matrix(A)
在lil 格式中,每一行的值都存储在一个列表中。
In [56]: Ml=M.tolil()
In [57]: Ml.data
Out[57]: array([[1, 2], [], [2, 3]], dtype=object)
取其中每一个的乘积:
In [58]: np.array([np.prod(i) for i in Ml.data])
Out[58]: array([ 2., 1., 6.])
csr 格式中的值存储为:
In [53]: M.data
Out[53]: array([1, 2, 2, 3], dtype=int32)
In [54]: M.indices
Out[54]: array([0, 1, 0, 2], dtype=int32)
In [55]: M.indptr
Out[55]: array([0, 2, 2, 4], dtype=int32)
indptr 给出行值的开始。 csr(和csc)矩阵上的计算代码通常执行这样的计算(但已编译):
In [94]: lst=[]; i=M.indptr[0]
In [95]: for j in M.indptr[1:]:
...: lst.append(np.product(M.data[i:j]))
...: i = j
In [96]: lst
Out[96]: [2, 1, 6]
使用Diavaker的测试矩阵:
In [137]: M.A
Out[137]:
array([[-1, 2, 0, 0],
[ 0, 0, 0, 0],
[ 2, 0, 3, 0],
[ 4, 5, 6, 0],
[ 1, 9, 0, 2]], dtype=int32)
上面的循环产生:
In [138]: foo(M)
Out[138]: [-2, 1, 6, 120, 18]
带有unique 和reduceat 的Divakar 代码
In [139]: divk(M)
Out[139]: array([ -2, 0, 6, 120, 18], dtype=int32)
(空行的不同值)。
使用indptr 减少操作很简单:
In [140]: np.multiply.reduceat(M.data,M.indptr[:-1])
Out[140]: array([ -2, 2, 6, 120, 18], dtype=int32)
需要修复空的第二行的值(indptr 的值为 [2,2,...],reduceat 使用 M.data[2])。
def wptr(M, empty_val=1):
res = np.multiply.reduceat(M.data, M.indptr[:-1])
mask = np.diff(M.indptr)==0
res[mask] = empty_val
return res
使用更大的矩阵
Mb=sparse.random(1000,1000,.1,format='csr')
这个wptr 比 Divaker 的版本快大约 30 倍。
更多关于计算稀疏矩阵行的值的讨论:
Scipy.sparse.csr_matrix: How to get top ten values and indices?