【问题标题】:List non zero elements from sparse matrix in python列出python中稀疏矩阵中的非零元素
【发布时间】:2017-12-14 05:21:26
【问题描述】:

如何以简单的一行代码(而且速度快!)列出csr_matrix 的所有非零元素?

我正在使用此代码:

edges_list = list([tuple(row) for row in np.transpose(A.nonzero())])
weight_list = [A[e] for e in edges_list]

但是执行需要相当长的时间。

【问题讨论】:

    标签: python sparse-matrix


    【解决方案1】:

    对于规范形式的 CSR 矩阵,直接访问数据数组:

    A.data
    

    但请注意,非规范形式的矩阵可能在其表示中包含显式零或重复条目,这将需要特殊处理。例如,

    # Merge duplicates and remove explicit zeros. Both operations modify A.
    # We sum duplicates first because they might sum to zero - for example,
    # if a 5 and a -5 are in the same spot, we have to sum them to 0 and then remove the 0.
    A.sum_duplicates()
    A.eliminate_zeros()
    
    # Now use A.data
    do_whatever_with(A.data)
    

    【讨论】:

    • 我如何知道它们是否是规范形式?
    • @Miguel:通常是因为数据源提供的保证。例如,如果您自己创建了矩阵,您可能知道您创建它的方式不会产生显式零或重复条目。
    • 好吧,我知道我自己创建它的场景。谢谢。
    【解决方案2】:

    您可以使用A.nonzero() 直接索引到A

    In [19]: A = np.random.randint(0, 3, (3, 3))
    
    In [20]: A
    Out[20]: 
    array([[2, 1, 1],
           [1, 2, 2],
           [0, 1, 0]])
    
    In [21]: A[A.nonzero()]
    Out[21]: array([2, 1, 1, 1, 2, 2, 1])
    

    结果和你的方法一样:

    In [22]: edges_list = list([tuple(row) for row in np.transpose(A.nonzero())])
    
    In [23]: [A[e] for e in edges_list]
    Out[23]: [2, 1, 1, 1, 2, 2, 1]
    

    而且显然要快很多(如果矩阵变大,速度会更快):

    In [25]: %timeit [A[e] for e in list([tuple(row) for row in np.transpose(A.nonzero())])]
    10000 loops, best of 3: 48 µs per loop
    
    In [26]: %timeit A[A.nonzero()]
    100000 loops, best of 3: 10.7 µs per loop
    

    也适用于scipycsr_matrix,尽管有更好的方法,如其他答案所示:

    In [30]: M = scipy.sparse.csr_matrix(A)
    
    In [31]: M[M.nonzero()]
    Out[31]: matrix([[2, 1, 1, 1, 2, 2, 1]], dtype=int32)
    

    【讨论】:

    • 这是一个常规的 NumPy 数组,而不是 SciPy CSR 矩阵。
    • @user2357112 老实说,我不知道这个问题是特定于 scipy 的。但这不应该仍然有效,并且更普遍适用吗?
    • 它仍然有效,但数组测试具有误导性。输出类型和结构与 scipy.sparse.csr_matrix 不同 - 查看结果如何是 numpy.matrix 而不是 ndarray。此外,稀疏矩阵索引的性能特征与常规数组索引有很大不同。
    • @user2357112 感谢您指出,正如我所说,我不知道这一点。我还是把这个留在这里,因为这个问题没有明确的标题或标记为scipy,其他人可能仍然觉得这很有用。
    【解决方案3】:

    只需使用A.data

    In [16]: from scipy.sparse import csr_matrix
    
    In [17]: A = csr_matrix([[1,0,0],[0,2,0]])
    
    In [18]: A.data
    Out[18]: array([1, 2])
    

    如果稀疏矩阵已被修改或为了安全起见,您应该使用:A.eliminate_zeros()

    In [19]: A[0,0] = 0
    
    In [20]: A.data
    Out[20]: array([0, 2])
    
    In [21]: A.eliminate_zeros()
    
    In [22]: A.data
    Out[22]: array([2])
    

    【讨论】:

    • 这可能返回零个元素——在A.data 之前尝试A[0,0] = 0。我认为您需要先添加A.eliminate_zeros()
    【解决方案4】:

    你可以像这样使用scipy.sparse.find

    >>> from scipy.sparse import csr_matrix, find
    >>> A = csr_matrix([[7.0, 8.0, 0],[0, 0, 9.0]])
    >>> find(A)
    (array([0, 0, 1], dtype=int32), array([0, 1, 2], 
    dtype=int32), array([ 7.,  8.,  9.]))
    

    https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.find.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-16
      相关资源
      最近更新 更多