假设我有一个二维矩阵作为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数组来实现这一点,但我不想这样做。还有其他办法吗?
非常感谢!
答案 0 :(得分:21)
对于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])
答案 1 :(得分:10)
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
答案 2 :(得分:5)
您可以使用
从CSR矩阵0 < i < X.shape[0] - 1
中删除行X
scipy.sparse.vstack([X[:i, :], X[i:, :]])
您可以分别删除X[1:, :]
或X[:-1, :]
的第一行或最后一行。删除一行中的多行可能需要滚动自己的功能。
对于除CSR之外的其他格式,这可能不一定有效,因为并非所有格式都支持行切片。
答案 3 :(得分:5)
除了@ 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
答案 4 :(得分:3)
要从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
您也可以通过右移乘以适当大小的J.T来删除列 最后,乘法在这种情况下是有效的,因为J非常稀疏。
答案 5 :(得分: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,:]
删除方法也没有做任何其他事情。
答案 6 :(得分:0)
使用@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]