如何在稀疏矩阵中查找零元素

How to find zero elements in a sparse matrix

我知道 scipy.sparse.find(A) returns 3 个数组 I、J、V,每个数组分别包含行、列和非零元素的值。

我想要的是一种对所有零元素执行相同操作(V 数组除外)的方法,而不必遍历矩阵,因为它太大了。

假设您有一个 scipy 稀疏数组并且导入了 find:

from itertools import product
I, J, _= find(your_sparse_array)
nonzero = zip(I, J)
nrows, ncols = your_sparse_array.shape
for a, b in product(range(nrows), range(ncols)):
    if (a,b) not in nonzero: print(a, b)

制作一个稀疏度为 10% 的小型稀疏矩阵:

In [1]: from scipy import sparse
In [2]: M = sparse.random(10,10,.1)
In [3]: M
Out[3]: 
<10x10 sparse matrix of type '<class 'numpy.float64'>'
    with 10 stored elements in COOrdinate format>

10 个非零值:

In [5]: sparse.find(M)
Out[5]: 
(array([6, 4, 1, 2, 3, 0, 1, 6, 9, 6], dtype=int32),
 array([1, 2, 3, 3, 3, 4, 4, 4, 5, 8], dtype=int32),
 array([ 0.91828586,  0.29763717,  0.12771201,  0.24986069,  0.14674883,
         0.56018409,  0.28643427,  0.11654358,  0.8784731 ,  0.13253971]))

如果矩阵的 100 个元素中有 10 个非零,则 90 个元素为零。您真的想要所有这些的索引吗?

wherenonzero 在密集等价物上给出相同的索引:

In [6]: A = M.A # dense
In [7]: np.where(A)
Out[7]: 
(array([0, 1, 1, 2, 3, 4, 6, 6, 6, 9], dtype=int32),
 array([4, 3, 4, 3, 3, 2, 1, 4, 8, 5], dtype=int32))

以及90个零值的索引:

In [8]: np.where(A==0)
Out[8]: 
(array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
        2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
        5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
        7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9], dtype=int32),
 array([0, 1, 2, 3, 5, 6, 7, 8, 9, 0, 1, 2, 5, 6, 7, 8, 9, 0, 1, 2, 4, 5, 6,
        7, 8, 9, 0, 1, 2, 4, 5, 6, 7, 8, 9, 0, 1, 3, 4, 5, 6, 7, 8, 9, 0, 1,
        2, 3, 4, 5, 6, 7, 8, 9, 0, 2, 3, 5, 6, 7, 9, 0, 1, 2, 3, 4, 5, 6, 7,
        8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 6, 7, 8, 9], dtype=int32))

这是 2 个形状为 (90,) 的数组,180 个整数,而不是密集数组本身的 100 个值。如果您的稀疏矩阵太大而无法转换为密集矩阵,那么它将太大而无法生成所有零索引(假设合理的稀疏性)。

print(M) 显示与找到的相同的三胞胎。 coo 格式的属性也给出了非零索引:

In [13]: M.row
Out[13]: array([6, 6, 3, 4, 1, 6, 9, 2, 1, 0], dtype=int32)
In [14]: M.col
Out[14]: array([1, 4, 3, 2, 3, 8, 5, 3, 4, 4], dtype=int32)

(有时对矩阵的操作可以将值设置为 0 而不会从属性中删除它们。因此 find/nonzero 采取额外的步骤来删除这些值(如果有的话)。)


我们也可以将 find 应用到 M==0 - 但稀疏会给我们一个警告。

In [15]: sparse.find(M==0)
/usr/local/lib/python3.5/dist-packages/scipy/sparse/compressed.py:213: SparseEfficiencyWarning: Comparing a sparse matrix with 0 using == is inefficient, try using != instead.
  ", try using != instead.", SparseEfficiencyWarning)

这与我一直警告的是同一件事 - 这一套的尺寸很大。结果数组与 Out[8].

中的相同