Python 检查Scipy稀疏矩阵的密度

Python 检查Scipy稀疏矩阵的密度,python,numpy,scipy,sparse-matrix,Python,Numpy,Scipy,Sparse Matrix,有没有一种好方法可以测量或检查scipy.sparse矩阵的密度 例如: import scipy.sparse import numpy as np row = np.array([0,3,1,0]) col = np.array([0,3,1,2]) data = np.array([4,5,7,9]) mat = scipy.sparse.coo_matrix((data,(row,col)), shape=(4,4)) print mat.todense() [[4 0 9 0

有没有一种好方法可以测量或检查scipy.sparse矩阵的密度

例如:

import scipy.sparse
import numpy as np

row  = np.array([0,3,1,0])
col  = np.array([0,3,1,2])
data = np.array([4,5,7,9])

mat = scipy.sparse.coo_matrix((data,(row,col)), shape=(4,4))
print mat.todense()

[[4 0 9 0]
 [0 7 0 0]
 [0 0 0 0]
 [0 0 0 5]]

可能会返回一些可以提供总体密度的一般统计信息,如每行平均占用率(即,第一行占用2/4个值,第二行占用1/4个值,第三行占用0/4个值,第四行占用1/4个值,因此平均占用率/密度为1/4)、STDEV、方差、,等等。也许有一种更好的密度度量可以应用,它不依赖于矩阵的大小(假设它足够大)。

一种方法是使用
getnnz()
方法来识别给定行、列或整个矩阵中非零项的数量

让我们从一个示例稀疏矩阵开始
sp_mat

sp_mat.todense()

matrix([[0, 1, 1, 1, 1],
        [1, 0, 1, 0, 0]])
整个矩阵中的非零元素计数:

sp_mat.getnnz()
# 6
给定行中的非零元素计数:

sp_mat[0,:].getnnz()
# 4
所有行的非零元素计数:

sp_mat.getnnz(axis=1)
# array([4, 2], dtype=int32)
列中的非零元素计数:

sp_mat[:,1].getnnz()
# 1
所有列的非零元素计数:

sp_mat.getnnz(axis=0)
#  array([1, 1, 2, 1, 1])
可将其与矩阵形状进行比较,以计算密度:

sp_mat.shape
# (2, 5)

我不知道有任何这样的密度函数,但您可以搜索
sparse
文档

对于整个数组,通过对每行的迭代,很容易得到非零元素的数量

mat.nnz
Out[55]: 4

[i.nnz for i in mat.tolil()]
Out[57]: [2, 1, 0, 1]
我使用了
tolil
,因为
coo
不允许行迭代(或索引)<代码>企业社会责任也会起作用

您还可以直接使用
lil
格式的属性,因为它们是列表的列表。这比迭代
lil
格式的行要快得多。该操作在每次迭代时创建一个新的稀疏矩阵,这完全是一个缓慢的操作

mal=mat.tolil()

mal.data
Out[65]: array([[4, 9], [7], [], [5]], dtype=object)

mal.rows
Out[67]: array([[0, 2], [1], [], [3]], dtype=object)

[len(i) for i in mal.rows]
Out[68]: [2, 1, 0, 1]
将其转换为数组,并计算所需的所有统计信息:

In [76]: s=np.array([len(i) for i in mal.rows])

In [77]: np.mean(s/4.)
Out[77]: 0.25

In [78]: np.std(s/4.)
Out[78]: 0.17677669529663689
将此行计数应用于密集阵列可能会更快

In [93]: timeit [np.count_nonzero(i) for i in mat.A]
10000 loops, best of 3: 44.3 µs per loop

In [94]: timeit [i.nnz for i in mat.tolil()]
100 loops, best of 3: 2.67 ms per loop

我刚刚意识到,使用稠密版本,至少可以在不迭代和布尔运算的情况下得到非零计数:

In [6]: (mat.A!=0).sum(axis=1)
Out[6]: array([2, 1, 0, 1])
(尽管对于这个小样本阵列,这比另一个密集版本要慢)

稀疏版本也可以工作,但速度较慢(但比迭代稀疏版本快)。主要是布尔测试;行求和是通过矩阵乘法完成的

In [9]: (mat!=0).sum(axis=1)
Out[9]: 
matrix([[2],
        [1],
        [0],
        [1]])
这是一种更快的稀疏求和方法:

In [13]: mat1=mat.tocsr(); mat1.data[:]=1;mat1.sum(axis=1)
Out[13]: 
matrix([[2],
        [1],
        [0],
        [1]])
tocsr
复制;我们将其
数据
更改为所有,并将它们相加


因此,如果速度很重要,您需要使用真实的大小矩阵进行自己的时间测试。

要获得
mat
的简单密度分数(即矩阵中非零元素的分数),我使用以下方法:

density=mat.getnnz()/np.prod(mat.shape)

您可以将mat中的所有元素计算为
all=sum(mat.count())
接下来,您可以将所有零计算为
zeros=all-count\u非零(mat)
根据这些值,可以将密度估计为
density=zeros/all

感谢@slaw对axis参数的建议。您的示例简洁而有用,但第0行的非零元素计数应该是4而不是3?谢谢@DavidChen,这是正确的。我更新了示例。