2011-01-14 21 views
26

Supponiamo di avere una matrice NxN M (lil_matrix o csr_matrix) da scipy.sparse, e voglio renderla (N + 1) xN dove M_modified [i, j] = M [i, j] per 0 < = i < N (e tutto j) e M [N, j] = 0 per tutti i j. Fondamentalmente, voglio aggiungere una riga di zeri alla fine di M e conservare il resto della matrice. C'è un modo per farlo senza copiare i dati?espandendo (aggiungendo una riga o colonna) una matrice scipy.sparse

risposta

4

Non penso che esista un modo per sfuggire alla copia. Entrambi questi tipi di matrici sparse memorizzano i propri dati come array Numpy (negli attributi data e indici per csr e negli attributi data e rows per lil) internamente e gli array Numpy non possono essere estesi.

aggiornamento con ulteriori informazioni:

LIL fa riposare per lista collegata, ma l'implementazione corrente non abbastanza all'altezza del nome. Gli array Numpy utilizzati per data e rows sono entrambi di tipo oggetto. Ciascuno degli oggetti in questi array sono in realtà elenchi Python (una lista vuota quando tutti i valori sono pari a zero in una riga). Gli elenchi Python non sono esattamente elenchi collegati, ma sono piuttosto vicini e francamente una scelta migliore a causa della ricerca O (1). Personalmente, non vedo immediatamente il punto di usare una serie di oggetti Numpy qui piuttosto che una semplice lista Python. Potresti facilmente cambiare l'attuale implementazione di lil per usare invece gli elenchi Python che ti permetteranno di aggiungere una riga senza copiare l'intera matrice.

+0

Se è abbastanza fondamentale per la vostra applicazione, si potrebbe essere in grado di implementare una nuova classe con l'interfaccia scipy.sparse che utilizza un tipo di dati più facilmente estendibile sotto il cofano. –

+1

Forse qualcuno più esperto sulla struttura dati sottostante potrebbe rispondere a questo. Pensavo che lil_matrix fosse implementato con liste collegate? – RandomGuy

+0

@scandido, controlla se la mia ultima aggiunta risponde alla tua domanda. –

8

Non so se stai ancora cercando una soluzione, ma forse altri possono esaminare hstack e vstack - http://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.hstack.html. Penso che possiamo definire una csr_matrix per l'unica riga aggiuntiva e quindi vstack con la matrice precedente.

+0

[codice sorgente per vstack] (https://github.com/scipy/scipy/blob/v0.19.0/scipy/sparse/construct.py#L461-L492) Come questo implica, restituisce una nuova copia dell'input matrici, quindi non abbastanza efficienti se vogliamo espandere una matrice ** in place **. – JenkinsY

24

Scipy non ha un modo per farlo senza copiare i dati ma è possibile farlo da soli modificando gli attributi che definiscono la matrice sparsa.

Ci sono 4 attributi che compongono il csr_matrix:

dati: Un array contenente i valori effettivi nella matrice

indici: Un array che contiene l'indice di colonna corrispondente a ciascun valore nei dati

indptr: una matrice che specifica l'indice prima del primo valore nei dati per ogni riga. Se la riga è vuota, l'indice è uguale alla colonna precedente.

forma: una tupla contenente la forma della matrice

Se siete semplicemente aggiungendo una fila di zeri in fondo tutto ciò che dovete fare è cambiare la forma e indptr per la matrice.

x = np.ones((3,5)) 
x = csr_matrix(x) 
x.toarray() 
>> array([[ 1., 1., 1., 1., 1.], 
      [ 1., 1., 1., 1., 1.], 
      [ 1., 1., 1., 1., 1.]]) 
# reshape is not implemented for csr_matrix but you can cheat and do it yourself. 
x._shape = (4,5) 
# Update indptr to let it know we added a row with nothing in it. So just append the last 
# value in indptr to the end. 
# note that you are still copying the indptr array 
x.indptr = np.hstack((x.indptr,x.indptr[-1])) 
x.toarray() 
array([[ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 0., 0., 0., 0., 0.]]) 

Ecco una funzione per gestire il caso più generale di vstacking di 2 csr_matrices. Continuerai a copiare gli array numpy sottostanti, ma è ancora significativamente più veloce del metodo vstack scipy.

def csr_vappend(a,b): 
    """ Takes in 2 csr_matrices and appends the second one to the bottom of the first one. 
    Much faster than scipy.sparse.vstack but assumes the type to be csr and overwrites 
    the first matrix instead of copying it. The data, indices, and indptr still get copied.""" 

    a.data = np.hstack((a.data,b.data)) 
    a.indices = np.hstack((a.indices,b.indices)) 
    a.indptr = np.hstack((a.indptr,(b.indptr + a.nnz)[1:])) 
    a._shape = (a.shape[0]+b.shape[0],b.shape[1]) 
    return a 
+1

Penso che si possa fare a meno di non tornare 'a', poiché gli argomenti delle funzioni sono passati per riferimento,' a' viene modificato direttamente anche all'interno dell'ambito della funzione. Inoltre, può esistere un analogo csc_happend (a, b)? – richizy

+0

Buona idea, per ripristinare semplicemente la forma. – Jan

Problemi correlati