通过交换行和列重新排列稀疏数组

时间:2013-03-01 10:18:46

标签: matlab numpy scipy sparse-matrix

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

一些问题

  • 我不认为排列矩阵非常适合这项任务,因为他们喜欢随机改变稀疏结构。即使只需要少量交换,操纵也会“倍增”所有列或行。

  • scipy.sparse中此任务的最佳稀疏矩阵表示是什么?

  • 非常欢迎有关实施的建议。

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

3 个答案:

答案 0 :(得分:4)

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格式,并根据它选择是先交换行还是列,以最大限度地减少转换。

答案 1 :(得分:0)

在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 ......

答案 2 :(得分:0)

我发现使用矩阵运算是最有效的。这是一个将行和/或列排列到指定顺序的函数。如果需要,可以对其进行修改以交换两个特定的行/列。

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