没有列为零的稀疏矩阵行

问题描述

我有一个这样的矩阵:

A = sp.csr_matrix(np.array(
      [[1,1,2,1],[0,0],[1,4,0]]))

我想获得所有列都不为零的所有行,这样我就可以得到它们的总和。或者作为一个数组:

rows = [True,False,True,False]
result = A[rows].sum()

或作为索引:

rows = [0,2]
result = A[rows].sum()

然而,我在第一部分被卡住了,弄清楚哪些行要包含在总和中,因为大多数结果似乎都在寻找相反的结果(所有列都为零的行)。

解决方法

numpy 数组比稀疏数组容易一些。如果您不介意将转换为 numpy 作为中间步骤,您可以通过

获得正确的行
(A.toarray() != 0).all(axis=1)

生产

array([ True,False,True,False])

然后在索引 A 时使用它:

A[(A.toarray() != 0).all(axis=1),:].sum()

返回 12

,
In [35]: from scipy import sparse
In [36]: A = sparse.csr_matrix(np.array(
    ...:       [[1,1,2,1],...:        [0,0],...:        [1,4,0]]))
In [37]: A
Out[37]: 
<4x4 sparse matrix of type '<class 'numpy.int64'>'
    with 10 stored elements in Compressed Sparse Row format>

稀疏不执行“所有/任何”类型的操作,因为它们将 0 视为重要值。

all 在密集等价物上效果很好:

In [41]: A.A.all(axis=1)
Out[41]: array([ True,False])

在稀疏类型上,我们可以将 dtype 转换为布尔值,并沿轴求和。然后测试它的完整值:

In [42]: A.astype(bool).sum(axis=1)
Out[42]: 
matrix([[4],[1],[4],[1]])
In [43]: A.astype(bool).sum(axis=1).A1==4
Out[43]: array([ True,False])

请注意,稀疏 sum 返回 np.matrix。我使用 A1 将其转换为一维数组。

如果矩阵不是太大,使用密集数组可能会更快。像 sum 这样的稀疏运算实际上是用矩阵乘法来执行的。

In [51]: A.astype(bool)@np.ones(4,int)
Out[51]: array([4,1])

或者我们可以将其转换为 lil 格式,然后查看“行”的长度:

In [67]: A.tolil().data
Out[67]: 
array([list([1,1]),list([2]),list([1,list([1])],dtype=object)
In [68]: [len(i) for i in A.tolil().data]
Out[68]: [4,1]

但是等等,还有更多。 indptrcsr 属性是:

In [69]: A.indptr
Out[69]: array([ 0,5,9,10],dtype=int32)
In [70]: np.diff(A.indptr)
Out[70]: array([4,dtype=int32)

我省略了一些测试时间,但最后一个显然是最快的!