2012-08-26 3 views
7

Angenommen, ich habe eine Matrix im CSR-Format, was ist der effizienteste Weg, um eine Zeile (oder Zeilen) auf Nullen zu setzen?scipy.sparse: Setze Zeile auf Nullen

Der folgende Code läuft ganz langsam:

A = A.tolil() 
A[indices, :] = 0 
A = A.tocsr() 

ich scipy.sparse.lil_matrix konvertieren musste, weil das CSR-Format weder Phantasie Indizierung zu unterstützen scheint noch Werte Scheiben einstellen.

+0

Nun, ich habe gerade versucht, ein '[A .__ SetItem __ ((i, j), 0) für i in Indizes für j im Bereich (A.shape [1])] 'und' SciPy' haben mir gesagt, dass 'SparseEfficiencyWarning: die Änderung der Sparsity-Struktur einer csr_matrix teuer ist. lil_matrix ist effizienter.' ... –

+0

keine Ahnung, ob scipy eine Unterstützung dafür hat, aber da es sich um eine CSR-Matrix handelt, kann dies effizient gehandhabt werden (zumindest von Hand). Eine Frage ist, möchten Sie das Sparsity-Muster ändern, oder sollten diese 0 nur numerisch 0 sein? – seberg

+0

Ich bin nicht sicher, was mit dem Sparsity-Muster gemeint ist.Ich fahre fort, ein System von Gleichungen zu lösen, indem ich die scipy.sparse.linalg.spsolve Funktion verwende. Ich hoffe, dass dies die Notwendigkeit feststellt, das Sparsity-Muster oder das Fehlen davon zu ändern. –

Antwort

5

Ich denke, SciPy gerade es nicht implementieren, aber das CSR-Format würde dies ganz gut unterstützen, lesen Sie bitte über den Wikipedia-Artikel über „Sparse Matrix“, was indptr usw. sind:

# A.indptr is an array, one for each row (+1 for the nnz): 

def csr_row_set_nz_to_val(csr, row, value=0): 
    """Set all nonzero elements (elements currently in the sparsity pattern) 
    to the given value. Useful to set to 0 mostly. 
    """ 
    if not isinstance(csr, scipy.sparse.csr_matrix): 
     raise ValueError('Matrix given must be of CSR format.') 
    csr.data[csr.indptr[row]:csr.indptr[row+1]] = value 

# Now you can just do: 
for row in indices: 
    csr_row_set_nz_to_val(A, row, 0) 

# And to remove zeros from the sparsity pattern: 
A.eliminate_zeros() 

Natürlich Dies entfernt 0s, die von einem anderen Ort mit eliminate_zeros aus dem Sparsity-Muster gesetzt wurden. Wenn Sie das (an diesem Punkt) tun wollen, hängt davon ab, was Sie wirklich tun, dh. Die Eliminierung kann sinnvoll sein, um zu verzögern, bis alle anderen Berechnungen, die neue Nullen hinzufügen, ebenfalls ausgeführt werden oder in manchen Fällen 0 Werte haben, die Sie später noch einmal ändern möchten. Daher wäre es sehr schlecht, sie zu eliminieren!

Sie könnten im Prinzip natürlich die eliminate_zeros und prune kurzschließen, aber das sollte eine Menge Ärger sein, und könnte sogar noch langsamer sein (weil Sie es nicht in C tun).


Details zu eliminiate_zeros (und Pflaume)

Die spärliche Matrix, im allgemeinen nicht Null-Elemente speichern, aber nur Geschäfte, in denen die Nicht-Null-Elementen (grob und mit verschiedenen Methoden). eliminate_zeros löscht alle Nullen in Ihrer Matrix aus dem Sparsity-Muster (dh es wird kein Wert für diese Position gespeichert, wenn vorher ein Wert gespeichert wurde, aber es 0 war). Eliminate ist schlecht, wenn Sie später eine 0 auf einen anderen Wert ändern möchten, da sonst Platz gespart wird.

Prune würde nur die gespeicherten Datenfelder verkleinern, wenn sie länger als nötig sind. Beachten Sie, dass, während ich zuerst A.prune() drin hatte, A.eliminiate_zeros() bereits Prune enthält.

+0

Danke! Das hat die Dinge erheblich beschleunigt! Ich würde gerne wissen, was die Elimination_zeros und Prune-Anweisungen dort tun? –

+0

Hinzugefügt einen (hoffentlich verständlichen) Satz. Beachten Sie, dass 'prune()' unnötig war, 'eliminate_zeros' bereits' prune' – seberg

0

Update auf die neueste Version von scipy. Es unterstützt ausgefallene Indexierung.

0

Sie können Matrix-Punkt-Produkt verwenden, um diese Nullsetzung zu erreichen. Da die Matrix, die wir verwenden, sehr spärlich ist (Diagonale mit Nullen für die Zeilen/Spalten, die wir auf Null setzen), sollte die Multiplikation effizient sein.

Sie eine der folgenden Funktionen benötigen:

import scipy.sparse 

def zero_rows(M, rows): 
    diag = scipy.sparse.eye(M.shape[0]).tolil() 
    for r in rows: 
     diag[r, r] = 0 
    return diag.dot(M) 

def zero_columns(M, columns): 
    diag = scipy.sparse.eye(M.shape[1]).tolil() 
    for c in columns: 
     diag[c, c] = 0 
    return M.dot(diag) 

Anwendungsbeispiel:

>>> A = scipy.sparse.csr_matrix([[1,0,3,4], [5,6,0,8], [9,10,11,0]]) 
>>> A 
<3x4 sparse matrix of type '<class 'numpy.int64'>' 
     with 9 stored elements in Compressed Sparse Row format> 
>>> A.toarray() 
array([[ 1, 0, 3, 4], 
     [ 5, 6, 0, 8], 
     [ 9, 10, 11, 0]], dtype=int64) 

>>> B = zero_rows(A, [1]) 
>>> B 
<3x4 sparse matrix of type '<class 'numpy.float64'>' 
     with 6 stored elements in Compressed Sparse Row format> 
>>> B.toarray() 
array([[ 1., 0., 3., 4.], 
     [ 0., 0., 0., 0.], 
     [ 9., 10., 11., 0.]]) 

>>> C = zero_columns(A, [1, 3]) 
>>> C 
<3x4 sparse matrix of type '<class 'numpy.float64'>' 
     with 5 stored elements in Compressed Sparse Row format> 
>>> C.toarray() 
array([[ 1., 0., 3., 0.], 
     [ 5., 0., 0., 0.], 
     [ 9., 0., 11., 0.]])