2015-02-23 19 views
5

Ho provato a inizializzare csc_matrix e csr_matrix da un elenco di valori (data, (rows, cols)) come suggerisce la documentazione.Ignorare le voci duplicate nella matrice sparse

sparse = csc_matrix((data, (rows, cols)), shape=(n, n)) 

Il problema è che, il metodo che in realtà sono per generare i vettori data, rows e cols introduce duplicati per alcuni punti. Per impostazione predefinita, scipy aggiunge i valori delle voci duplicate. Tuttavia, nel mio caso, quei duplicati hanno esattamente lo stesso valore in data per un dato (row, col).

Quello che sto cercando di ottenere è di far scipy ignorare la seconda voce se ne esiste già una, invece di aggiungerle.

Ignorando il fatto che potrei migliorare l'algoritmo di generazione per evitare di generare duplicati, c'è un parametro o un altro modo di creare una matrice sparsa che ignora i duplicati?

Attualmente due voci con data = [4, 4]; cols = [1, 1]; rows = [1, 1]; generare una matrice sparsa cui valore è (1,1)8 mentre il valore desiderato è 4.

>>> c = csc_matrix(([4, 4], ([1,1],[1,1])), shape=(3,3)) 
>>> c.todense() 
matrix([[0, 0, 0], 
     [0, 8, 0], 
     [0, 0, 0]]) 

Sono anche consapevole del fatto che io potessi filtrare utilizzando un 2-dimensionale funzione NumPy unique, ma le liste sono abbastanza grandi, quindi questo non è davvero un'opzione valida.

Altre possibili risposte alla domanda: esiste un modo per specificare cosa fare con i duplicati? vale a dire mantenendo min o max anziché il valore predefinito sum?

+0

Sono quasi sicuro che la risposta è no, non esiste un modo integrato di modificare il comportamento per i duplicati. Non dovresti essere troppo veloce a scartare l'uso di 'np.unique' però: non importa quanto siano grandi le tue liste, scipy le convertirà in array e farà operazioni simili sotto il cofano, quindi non c'è ragione per cui tu non dovrebbe tentare di – Jaime

+1

'np.unique' è 1d, quindi la gestione di queste coordinate 2D richiederà uno sforzo extra. – hpaulj

+1

Vero, ma trucchi come [questo] (http://stackoverflow.com/questions/16970982/find-unique-rows-in-numpy-array) lo rendono 2D. –

risposta

4

Creazione di una matrice dok intermediario funziona nel tuo esempio:

In [410]: c=sparse.coo_matrix((data, (cols, rows)),shape=(3,3)).todok().tocsc() 

In [411]: c.A 
Out[411]: 
array([[0, 0, 0], 
     [0, 4, 0], 
     [0, 0, 0]], dtype=int32) 

Una matrice coo mette gli array di input in sue data, col, row attributi senza modifiche. La somma non si verifica fino a quando non viene convertita in csc.

todok carica il dizionario direttamente dagli attributi coo. Crea il dok matrice di vuoto e lo riempie con:

dok.update(izip(izip(self.row,self.col),self.data)) 

Quindi, se ci sono duplicati (row,col) valori, è l'ultimo che rimane. Questo utilizza l'hashing del dizionario standard Python per trovare le chiavi univoche.


Ecco un modo per utilizzare np.unique. Ho dovuto costruire un array di oggetti speciali, perché unique funziona su 1d e abbiamo un indicizzazione 2D.

In [479]: data, cols, rows = [np.array(j) for j in [[1,4,2,4,1],[0,1,1,1,2],[0,1,2,1,1]]] 

In [480]: x=np.zeros(cols.shape,dtype=object) 

In [481]: x[:]=list(zip(rows,cols)) 

In [482]: x 
Out[482]: array([(0, 0), (1, 1), (2, 1), (1, 1), (1, 2)], dtype=object) 

In [483]: i=np.unique(x,return_index=True)[1] 

In [484]: i 
Out[484]: array([0, 1, 4, 2], dtype=int32) 

In [485]: c1=sparse.csc_matrix((data[i],(cols[i],rows[i])),shape=(3,3)) 

In [486]: c1.A 
Out[486]: 
array([[1, 0, 0], 
     [0, 4, 2], 
     [0, 1, 0]], dtype=int32) 

Non ho idea di quale approccio sia più veloce.


Un modo alternativo di ottenere l'indice univoco, secondo liuengo's link:

rc = np.vstack([rows,cols]).T.copy() 
dt = rc.dtype.descr * 2 
i = np.unique(rc.view(dt), return_index=True)[1] 

rc deve possedere i propri dati al fine di modificare la dtype con vista, quindi il .T.copy().

In [554]: rc.view(dt) 
Out[554]: 
array([[(0, 0)], 
     [(1, 1)], 
     [(2, 1)], 
     [(1, 1)], 
     [(1, 2)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4')]) 
+0

Sembra un bel trucco. Non posso provarlo adesso, ci vuole un sacco di tempo/memoria per la conversione tra i tipi? –

+0

todok() non ignora i duplicati a scipy 0.19 –

+0

Sì, 'coo.todok' ora include una riga' self.sum_duplicates() '. La soluzione è fare l'aggiornamento come descrivo, ma senza questo 'sum'. – hpaulj

Problemi correlati