检查 Scipy 稀疏矩阵的密度
Check Density of a 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]
[0 7 0 0]
[0 0 0 0]
[0 0 0 5]]
也许 return 可以给我总体密度的一般统计数据,例如每行的平均占用率(即第一行占用 2/4 值,第二行占用 1/4,第三行占用 0/ 4,第四行占据 1/4,因此平均值 occupancy/density 将是 1/4),stddev,方差等。也许有一个更好的密度度量可以应用,它不依赖于大小矩阵(假设它足够大)。
一种方法是使用 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
不允许行迭代(或索引)。 csr
也可以。
您也可以直接使用 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
复制;我们把它的 data
改成所有的,然后求和。
因此,如果速度很重要,您需要使用实际尺寸矩阵进行自己的时间测试。
为了获得 mat
的简单密度分数(即矩阵中 non-zero 元素的分数),我使用类似的东西;
density = mat.getnnz() / np.prod(mat.shape)
您可以将 mat 中的所有元素计数为
all=sum(mat.count())
接下来,您可以将所有零都算作
zeros=all-count_nonzero(mat)
根据这些值,您可以将密度估计为
density=zeros/all
有没有好的方法来测量或检查 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]]
也许 return 可以给我总体密度的一般统计数据,例如每行的平均占用率(即第一行占用 2/4 值,第二行占用 1/4,第三行占用 0/ 4,第四行占据 1/4,因此平均值 occupancy/density 将是 1/4),stddev,方差等。也许有一个更好的密度度量可以应用,它不依赖于大小矩阵(假设它足够大)。
一种方法是使用 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
不允许行迭代(或索引)。 csr
也可以。
您也可以直接使用 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
复制;我们把它的 data
改成所有的,然后求和。
因此,如果速度很重要,您需要使用实际尺寸矩阵进行自己的时间测试。
为了获得 mat
的简单密度分数(即矩阵中 non-zero 元素的分数),我使用类似的东西;
density = mat.getnnz() / np.prod(mat.shape)
您可以将 mat 中的所有元素计数为
all=sum(mat.count())
接下来,您可以将所有零都算作
zeros=all-count_nonzero(mat)
根据这些值,您可以将密度估计为
density=zeros/all