25

假设我有一个二维矩阵作为 numpy 数组。如果我想删除此矩阵中具有特定索引的行,我使用numpy.delete(). 这是我的意思的一个例子:

In [1]: my_matrix = numpy.array([
   ...:     [10, 20, 30, 40, 50],
   ...:     [15, 25, 35, 45, 55],
   ...:     [95, 96, 97, 98, 99]
   ...: ])
In [2]: numpy.delete(my_matrix, [0, 2], axis=0)
Out[2]: array([[15, 25, 35, 45, 55]])

我正在寻找一种方法来使用scipy.sparse包中的矩阵执行上述操作。我知道可以通过将整个矩阵转换为一个 numpy 数组来做到这一点,但我不想这样做。有没有其他方法可以做到这一点?

非常感谢!

4

7 回答 7

26

对于 CSR,这可能是最有效的就地方式:

def delete_row_csr(mat, i):
    if not isinstance(mat, scipy.sparse.csr_matrix):
        raise ValueError("works only for CSR format -- use .tocsr() first")
    n = mat.indptr[i+1] - mat.indptr[i]
    if n > 0:
        mat.data[mat.indptr[i]:-n] = mat.data[mat.indptr[i+1]:]
        mat.data = mat.data[:-n]
        mat.indices[mat.indptr[i]:-n] = mat.indices[mat.indptr[i+1]:]
        mat.indices = mat.indices[:-n]
    mat.indptr[i:-1] = mat.indptr[i+1:]
    mat.indptr[i:] -= n
    mat.indptr = mat.indptr[:-1]
    mat._shape = (mat._shape[0]-1, mat._shape[1])

在 LIL 格式中,它甚至更简单:

def delete_row_lil(mat, i):
    if not isinstance(mat, scipy.sparse.lil_matrix):
        raise ValueError("works only for LIL format -- use .tolil() first")
    mat.rows = np.delete(mat.rows, i)
    mat.data = np.delete(mat.data, i)
    mat._shape = (mat._shape[0] - 1, mat._shape[1])
于 2012-10-25T23:21:58.297 回答
13

Pv.s 的答案是一个良好而可靠的就地解决方案,需要

a = scipy.sparse.csr_matrix((100,100), dtype=numpy.int8)
%timeit delete_row_csr(a.copy(), 0)
10000 loops, best of 3: 80.3 us per loop

对于任何数组大小。由于布尔索引适用于稀疏矩阵,至少在 中scipy >= 0.14.0,我建议在要删除多行时使用它:

def delete_rows_csr(mat, indices):
    """
    Remove the rows denoted by ``indices`` form the CSR sparse matrix ``mat``.
    """
    if not isinstance(mat, scipy.sparse.csr_matrix):
        raise ValueError("works only for CSR format -- use .tocsr() first")
    indices = list(indices)
    mask = numpy.ones(mat.shape[0], dtype=bool)
    mask[indices] = False
    return mat[mask]

此解决方案需要更长的时间来移除单行

%timeit delete_rows_csr(a.copy(), [50])
1000 loops, best of 3: 509 us per loop

但是对于删除多行更有效,因为执行时间几乎不会随着行数的增加而增加

%timeit delete_rows_csr(a.copy(), numpy.random.randint(0, 100, 30))
1000 loops, best of 3: 523 us per loop
于 2014-10-22T10:04:35.900 回答
8

除了@loli 版本的@pv 答案之外,我还扩展了它们的功能以允许通过 CSR 矩阵上的索引删除和/或列。

import numpy as np
from scipy.sparse import csr_matrix

def delete_from_csr(mat, row_indices=[], col_indices=[]):
    """
    Remove the rows (denoted by ``row_indices``) and columns (denoted by ``col_indices``) from the CSR sparse matrix ``mat``.
    WARNING: Indices of altered axes are reset in the returned matrix
    """
    if not isinstance(mat, csr_matrix):
        raise ValueError("works only for CSR format -- use .tocsr() first")

    rows = []
    cols = []
    if row_indices:
        rows = list(row_indices)
    if col_indices:
        cols = list(col_indices)

    if len(rows) > 0 and len(cols) > 0:
        row_mask = np.ones(mat.shape[0], dtype=bool)
        row_mask[rows] = False
        col_mask = np.ones(mat.shape[1], dtype=bool)
        col_mask[cols] = False
        return mat[row_mask][:,col_mask]
    elif len(rows) > 0:
        mask = np.ones(mat.shape[0], dtype=bool)
        mask[rows] = False
        return mat[mask]
    elif len(cols) > 0:
        mask = np.ones(mat.shape[1], dtype=bool)
        mask[cols] = False
        return mat[:,mask]
    else:
        return mat
于 2017-08-03T13:55:49.967 回答
6

0 < i < X.shape[0] - 1您可以从 CSR 矩阵X中删除行

scipy.sparse.vstack([X[:i, :], X[i:, :]])

您可以分别用X[1:, :]或删除第一行或最后一行。X[:-1, :]一次删除多行可能需要滚动您自己的函数。

对于 CSR 以外的其他格式,这可能不一定有效,因为并非所有格式都支持行切片。

于 2012-10-25T21:34:13.490 回答
5

要从 A 中删除第 i 行,只需使用左矩阵乘法:

B = J*A

其中 J 是删除第 i 行的稀疏单位矩阵。
左乘 J 的转置将在 B 的第 i 行插入一个零向量,这使得这个解决方案更通用一些。

A0 = J.T * B

为了构造 J 本身,我在稀疏对角矩阵上使用了 pv. 的解决方案,如下所示(对于这种特殊情况,可能有更简单的解决方案?)

def identity_minus_rows(N, rows):
    if np.isscalar(rows):
        rows = [rows]
    J = sps.diags(np.ones(N), 0).tocsr()  # make a diag matrix
    for r in sorted(rows):
        J = delete_row_csr(J, r)
    return J

您还可以通过右乘以适当大小的 JT 来删除列。
最后,在这种情况下,乘法是有效的,因为 J 非常稀疏。

于 2015-12-16T00:12:33.060 回答
2

请注意,稀疏矩阵在某种程度上支持花式索引。所以你可以做的是:

mask = np.ones(len(mat), dtype=bool)
mask[rows_to_delete] = False
# unfortunatly I think boolean indexing does not work:
w = np.flatnonzero(mask)
result = s[w,:]

delete 方法也没有真正做任何其他事情。

于 2012-10-26T10:07:02.193 回答
2

使用@loli 实现,在这里我留下一个删除列的函数:

def delete_cols_csr(mat, indices):
    """
    Remove the cols denoted by ``indices`` form the CSR sparse matrix ``mat``.
    """
    if not isinstance(mat, csr_matrix):
        raise ValueError("works only for CSR format -- use .tocsr() first")
    indices = list(indices)
    mask = np.ones(mat.shape[1], dtype=bool)
    mask[indices] = False
    return mat[:,mask]
于 2018-04-30T00:42:06.630 回答