在Python中的稀疏矩阵中按行查找非零条目的快速方法

时间:2014-07-16 21:00:02

标签: python numpy matrix

我试图在稀疏矩阵中按行找到非零项的索引:scipy.sparse.csc_matrix。到目前为止,我正在遍历矩阵中的每一行,并使用

numpy.nonzero()

到每一行以获取非零列索引。但是这种方法需要花费一个多小时才能找到每行的非零列条目。有快速的方法吗?谢谢!

5 个答案:

答案 0 :(得分:7)

使用.nonzero()方法。

indices = sp_matrix.nonzero()

如果您希望索引为(row, column)元组,则可以使用zip

indices = zip(*sp_matrix.nonzero())

答案 1 :(得分:3)

如果使用coo_matrix,这将非常简单,并且coo / csr / csc之间的转换速度非常快。分别获取所有行和列索引可以按如下方式完成:

sp_matrix = sp_matrix.tocoo()
row_ind = sp_matrix.row
col_ind = sp_matrix.col

但是你也可以同时为这些稀疏矩阵类型获得两组索引,这可能是最简单的:

rows, cols = X.nonzero()

如果需要在特定行中查找值,csc和csr矩阵将返回按行排序的非零条目,现在,铜似乎返回按列排序的索引。

In [1]: X = coo_matrix(([1, 2, 3, 4, 5, 6], ([0, 2, 2, 0, 1, 2], [0, 0, 1, 2, 2, 2])))

In [2]: X.todense()
Out[2]: 
matrix([[1, 0, 4],
        [0, 0, 5],
        [2, 3, 6]])

In [3]: X.nonzero()
Out[3]: 
(array([0, 2, 2, 0, 1, 2], dtype=int32),
 array([0, 0, 1, 2, 2, 2], dtype=int32))

In [4]: X.tocsr().nonzero()
Out[4]: 
(array([0, 0, 1, 2, 2, 2], dtype=int32),
 array([0, 2, 2, 0, 1, 2], dtype=int32))

答案 2 :(得分:3)

CSR矩阵相对简单,因此您可以随时执行:

>>> a = sps.rand(5, 5, .2, format='csc')
>>> a.A
array([[ 0.        ,  0.        ,  0.68642384,  0.        ,  0.        ],
       [ 0.46120599,  0.        ,  0.83253467,  0.        ,  0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.07074811],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.21190832,  0.        ,  0.        ,  0.        ]])
>>> b = a.tocsr()
>>> np.split(b.indices, b.indptr[1:-1])
[array([2]), array([0, 2]), array([4]), array([], dtype=float64), array([1])]

答案 3 :(得分:2)

我假设您的矩阵不对称,否则在一行中查找所有非零条目与在一列中查找所有这些条目相同。您正在使用的矩阵的维度是多少,平均每列有多少非零条目?

如果您的矩阵有m行和n列,并且您以CSC格式存储它,则可以在O(d)时间内返回列中的所有非零条目,其中d列中的非零条目数,但无法以小于O(n)的形式返回行中的所有非零条目;你必须遍历整行。

我会以CSR格式制作矩阵的副本并从中获取行而不是原始CSC矩阵。当然,你当然会使用两倍的内存,所以希望它不会那么大,以免排除额外的开销。这看起来像这样:

A = csc_matrix((m, n), dtype = float)
<fill A>
B = csr_matrix(A)

for i in range(m):
    _, cols = B[i, :].nonzero()
    for j in cols:
        <do some stuff>

使用COO格式,因为在最坏的情况下获取给定行中的所有非零条目可能需要O(nnz)时间,其中nnz是整个矩阵的非零项数。

如果您发现自己不得不经常使用稀疏矩阵,您可能需要查看this book。它描述了许多常见的和不常见的稀疏矩阵格式,并说明了它们之间的一些差异。没有一种最好的存储格式;他们都有自己的权衡。

答案 4 :(得分:0)

您希望这些指数采用何种形式?例如

x=sparse.csr_matrix([[1,2,0,3,0,0],[0,0,0,1,0,0]])

In [15]: for r in x:
   ....:     print r.nonzero()

(array([0]), array([0]))
(array([0, 0]), array([0, 2]))
(array([0, 0, 0]), array([0, 1, 2]))

In [30]: [r.nonzero()[1] for r in x]  # or as list
Out[30]: [array([0]), array([0, 2]), array([0, 1, 2])]

In [16]: x.nonzero()
Out[16]: (array([0, 1, 1, 2, 2, 2]), array([0, 0, 2, 0, 1, 2]))
整个矩阵上的

nonzero具有相同的数字,但它们不会分成子列表。但tolil格式与列表列表具有相同的信息。

In [18]: xl=x.tolil()
In [19]: xl.rows
Out[19]: array([[0], [0, 2], [0, 1, 2]], dtype=object)

In [23]: xc=x.tocoo()
In [24]: xc.row
Out[24]: array([0, 1, 2, 2, 1, 2])
In [25]: xc.col
Out[25]: array([0, 0, 0, 1, 2, 2])

coo格式中,存在相同的索引,但顺序不同。但首先将其转换为csr,订单为

In [29]: x.tocsr().tocoo().col
Out[29]: array([0, 0, 2, 0, 1, 2])