2012-08-26 9 views
7

Supponiamo di avere una matrice nel formato CSR, qual è il modo più efficiente per impostare una riga (o una riga) su zeri?scipy.sparse: imposta la riga sugli zeri

Il seguente codice viene eseguito molto lentamente:

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

ho dovuto convertire in scipy.sparse.lil_matrix perché il formato CSR sembra sostenere né l'indicizzazione di speciale e nemmeno l'impostazione dei valori a fette.

+0

Beh, ho appena provato un '[A .__ setitem __ ((i, j), 0) per i in indici per j in range (A.shape [1])] 'e' SciPy' mi hanno detto che 'SparseEfficiencyWarning: cambiare la struttura di sparsity di un csr_matrix è costoso. lil_matrix è più efficiente. ... –

+0

non ha idea se scipy abbia qualche supporto per questo, ma dato che è una matrice CSR, questo può essere gestito in modo efficiente (a mano almeno). Una domanda è, vuoi cambiare il pattern di sparsity, o dovrebbero quegli 0 essere solo numericamente 0? – seberg

+0

Non sono sicuro di cosa si intenda per lo schema di sparsità.Procedo alla risoluzione di un sistema di equazioni utilizzando la funzione scipy.sparse.linalg.spsolve. Spero che questo stabilisca la necessità di cambiare lo schema di sparsità, o la sua mancanza. –

risposta

5

Credo SciPy proprio non attuarlo, ma il formato CSR avrebbero sostenuto abbastanza bene, si prega di leggere l'articolo di Wikipedia sulla "matrice Sparse" di quello che indptr, ecc, sono:

# 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() 

Naturalmente questo rimuove gli 0 che sono stati impostati da un altro posto con eliminate_zeros dal modello di sparsità. Se vuoi farlo (a questo punto) dipende da cosa stai facendo veramente, cioè. l'eliminazione potrebbe avere senso ritardare fino a quando tutti gli altri calcoli che potrebbero aggiungere nuovi zero vengono eseguiti, o in alcuni casi si possono avere valori 0, che si desidera modificare di nuovo in seguito, quindi sarebbe molto brutto eliminarli!

In linea di principio è possibile, naturalmente, cortocircuitare eliminate_zeros e prune, ma questo dovrebbe comportare molti problemi e potrebbe anche essere più lento (perché non lo si farà in C).


dettagli circa eliminiate_zeros (e prugna)

La matrice sparsa, non generalmente non salva zero elementi, ma solo magazzini in cui gli elementi diversi da zero sono (approssimativamente e con vari metodi). eliminate_zeros rimuove tutti gli zeri nella matrice dal modello di sparsità (ad esempio non è stato memorizzato alcun valore per quella posizione, quando prima era un file memorizzato, ma era 0). Eliminare è sbagliato se si desidera modificare uno 0 in un valore diverso lateron, altrimenti risparmia spazio.

Prune ridurrebbe solo gli array di dati memorizzati quando sono più lunghi del necessario. Si noti che mentre prima avevo A.prune() lì, A.eliminiate_zeros() include già prugna.

+0

Grazie! Ciò ha accelerato notevolmente le cose! Mi piacerebbe sapere cosa ci fanno le dichiarazioni delete_zeros e prune? –

+0

Aggiunta una frase (si spera comprensibile). Si noti che 'prune()' non era necessario, 'delete_zeros' chiama già' prune' – seberg

0

Aggiornamento all'ultima versione di scipy. Supporta l'indicizzazione di fantasia.

0

È possibile utilizzare il prodotto a matrice di punti per ottenere tale azzeramento. Dato che la matrice che useremo è molto sparsa (diagonale con zeri per le righe/colonne che eliminiamo), la moltiplicazione dovrebbe essere efficiente.

Avrete bisogno di una delle seguenti funzioni: ad esempio

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) 

Usage:

>>> 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.]]) 
Problemi correlati