2012-10-25 41 views
17

假設我有一個二維矩陣作爲一個numpy數組。如果我想刪除矩陣中具有特定索引的行,我使用numpy.delete()。這裏是我的意思的例子:是否有稀疏矩陣的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數組來完成這個工作,但我不想那樣做。有沒有其他的方式呢?

非常感謝!

回答

3

您可以從企業社會責任矩陣X刪除行0 < i < X.shape[0] - 1

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

您可以刪除第一個或最後一行分別X[1:, :]X[:-1, :]。刪除一行中的多行可能需要滾動您自己的功能。

對於除CSR之外的其他格式,這可能不一定起作用,因爲並非所有格式都支持行分片。

+0

哦,親愛的,這很費力,似乎是刪除多行相當複雜。如果這是做到這一點的唯一方式,那麼爲了我的目的,將矩陣轉換爲一個numpy數組可能更好,儘管效率很低。 – pemistahl

15

對於企業社會責任,這可能是做就地最有效的方式:

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

注意,稀疏矩陣支持花哨的索引,以一定程度上。所以你可以做的是這樣的:

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,:] 

刪除方法並沒有做任何事情。

7

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 
0

從一個簡單的使用左矩陣乘法刪除第i行:

B = J*A 

其中J是一個稀疏的單位矩陣與第i行除去。
左乘以J的轉置會將零向量插回到B的第i行,這使得這個解決方案更通用一些。

A0 = J.T * B 

構建Ĵ本身,我用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非常稀疏。

+0

也許他想通過乘法(即使行/列爲零)來刪除而不是邏輯擦除。 –

0

除了@蘿莉版的@ 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``) form 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