【问题标题】:Rearrange sparse arrays by swapping rows and columns通过交换行和列重新排列稀疏数组
【发布时间】:2013-02-15 19:25:15
【问题描述】:

我有大型但稀疏的数组,我想通过交换行和列来重新排列它们。在scipy.sparse 中执行此操作的好方法是什么?

一些问题

  • 我认为置换矩阵不太适合这项任务,因为它们喜欢随机改变稀疏结构。并且操作将始终“乘以”所有列或行,即使只需要少量交换。

  • 对于这项任务,scipy.sparse 中的最佳稀疏矩阵表示是什么?

  • 非常欢迎提出实施建议。

我也用 Matlab 标记了这个问题,因为这个问题可能会找到不一定是 scipy 特定的答案。

【问题讨论】:

  • 我需要这个用于特定的实现。然而,正如一位同事向我指出的那样,一般来说,人们不会对稀疏矩阵进行排列。稀疏矩阵A 通常用作线性映射y=Ax,例如在迭代求解器中。因此,这种交换可以通过在A 周围编写一个包装器来更好地实现,交换输入向量x 的条目(这是A 中的列交换)或y 的条目(这是行交换)。

标签: matlab numpy scipy sparse-matrix


【解决方案1】:

我发现使用矩阵运算是最有效的。这是一个将行和/或列排列为指定顺序的函数。如果您愿意,可以修改它以交换两个特定的行/列。

from scipy import sparse

def permute_sparse_matrix(M, row_order=None, col_order=None):
    """
    Reorders the rows and/or columns in a scipy sparse matrix to the specified order.
    """
    if row_order is None and col_order is None:
        return M
    
    new_M = M
    if row_order is not None:
        I = sparse.eye(M.shape[0]).tocoo()
        I.row = I.row[row_order]
        new_M = I.dot(new_M)
    if col_order is not None:
        I = sparse.eye(M.shape[1]).tocoo()
        I.col = I.col[col_order]
        new_M = new_M.dot(I)
    return new_M

【讨论】:

    【解决方案2】:

    CSC 格式保存所有非零条目的行索引列表,CSR 格式保存所有非零条目的列索引列表。我认为您可以利用它来交换以下内容,并且我认为它不应该有任何副作用:

    def swap_rows(mat, a, b) :
        mat_csc = scipy.sparse.csc_matrix(mat)
        a_idx = np.where(mat_csc.indices == a)
        b_idx = np.where(mat_csc.indices == b)
        mat_csc.indices[a_idx] = b
        mat_csc.indices[b_idx] = a
        return mat_csc.asformat(mat.format)
    
    def swap_cols(mat, a, b) :
        mat_csr = scipy.sparse.csr_matrix(mat)
        a_idx = np.where(mat_csr.indices == a)
        b_idx = np.where(mat_csr.indices == b)
        mat_csr.indices[a_idx] = b
        mat_csr.indices[b_idx] = a
        return mat_csr.asformat(mat.format)
    

    你现在可以这样做:

    >>> mat = np.zeros((5,5))
    >>> mat[[1, 2, 3, 3], [0, 2, 2, 4]] = 1
    >>> mat = scipy.sparse.lil_matrix(mat)
    >>> mat.todense()
    matrix([[ 0.,  0.,  0.,  0.,  0.],
            [ 1.,  0.,  0.,  0.,  0.],
            [ 0.,  0.,  1.,  0.,  0.],
            [ 0.,  0.,  1.,  0.,  1.],
            [ 0.,  0.,  0.,  0.,  0.]])
    >>> swap_rows(mat, 1, 3)
    <5x5 sparse matrix of type '<type 'numpy.float64'>'
        with 4 stored elements in LInked List format>
    >>> swap_rows(mat, 1, 3).todense()
    matrix([[ 0.,  0.,  0.,  0.,  0.],
            [ 0.,  0.,  1.,  0.,  1.],
            [ 0.,  0.,  1.,  0.,  0.],
            [ 1.,  0.,  0.,  0.,  0.],
            [ 0.,  0.,  0.,  0.,  0.]])
    >>> swap_cols(mat, 0, 4)
    <5x5 sparse matrix of type '<type 'numpy.float64'>'
        with 4 stored elements in LInked List format>
    >>> swap_cols(mat, 0, 4).todense()
    matrix([[ 0.,  0.,  0.,  0.,  0.],
            [ 0.,  0.,  0.,  0.,  1.],
            [ 0.,  0.,  1.,  0.,  0.],
            [ 1.,  0.,  1.,  0.,  0.],
            [ 0.,  0.,  0.,  0.,  0.]])
    

    我使用 LIL 矩阵来展示如何保留输出的类型。在您的应用程序中,您可能希望已经是 CSC 或 CSR 格式,并根据它选择是否首先交换行或列,以最大限度地减少转换。

    【讨论】:

    • 谢谢@Jaime,这似乎就是我想要的。它表明我应该更加熟悉稀疏格式。
    • @Jan 您可能想再测试一下,我认为上面的示例有效,因为所有非零条目都是相同的。我现在没有时间,但稍后会更详细地研究它。还有另一个数组mat.indptr,可能也需要一些更改。 The wikipedia article on the Yale sparse format 拥有所需的所有信息,以防您想亲自尝试!
    • 我会测试它并让你知道...感谢来源。
    • @Jan 它应该可以正常工作,对于噪音感到抱歉。在玩弄indices 参数后,您可以运行.sort_indices() 以使其成为更标准的形式。但是indptr 将在这些变化中保持不变。
    • @Jan 如果它适合你,那么一切都很好。我认为您可以使用更多的 numpy 来摆脱 for 循环,但它可能会混淆代码,并且取决于您拥有多少数据和移动多少列,性能不会太明显。跨度>
    【解决方案3】:

    在 Matlab 中,您可以按照自己喜欢的方式索引列和行:

    Matrix = speye(10);
    mycolumnorder = [1 2 3 4 5 6 10 9 8 7];
    myroworder = [4 3 2 1 5 6 7 8 9 10];
    Myorderedmatrix = Matrix(myroworder,mycolumnorder);
    

    我认为这保留了稀疏性...虽然不知道 scipy...

    【讨论】:

      猜你喜欢
      • 2017-02-07
      • 2011-03-14
      • 1970-01-01
      • 1970-01-01
      • 2017-06-23
      • 1970-01-01
      • 1970-01-01
      • 2012-02-09
      • 1970-01-01
      相关资源
      最近更新 更多