2015-02-23 19 views
5

Ich habe versucht, csc_matrix und csr_matrix aus einer Liste von (data, (rows, cols)) Werte wie in der Dokumentation vorgeschlagen initialisieren.Ignorieren doppelte Einträge in Sparse-Matrix

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

Das Problem besteht darin, dass das Verfahren, das ich habe tatsächlich zur Erzeugung des data, rows und cols Vektoren Duplikate für einige Punkte führt. Standardmäßig fügt scipy die Werte der doppelten Einträge hinzu. In meinem Fall haben diese Duplikate jedoch genau denselben Wert in data für eine gegebene (row, col).

Was ich versuche zu erreichen ist, scipy den zweiten Eintrag zu ignorieren, wenn bereits eins existiert, anstatt sie hinzuzufügen.

Wenn ich die Tatsache ignoriere, dass ich den Generierungsalgorithmus verbessern kann, um die Erzeugung von Duplikaten zu vermeiden, gibt es einen Parameter oder eine andere Möglichkeit, eine dünn besetzte Matrix zu erstellen, die Duplikate ignoriert?

Derzeit zwei Einträge mit data = [4, 4]; cols = [1, 1]; rows = [1, 1]; erzeugen eine Sparse-Matrix, den Wert bei (1,1)8, während der gewünschte Wert 4 ist.

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

Ich bin auch bewusst, dass ich sie durch die Verwendung einer 2-dimensionale numpy unique Funktion filtern können, aber Listen sind ziemlich groß, sodass dies nicht wirklich eine gültige Option ist.

Andere mögliche Antwort auf die Frage: Gibt es eine Möglichkeit zu spezifizieren, was mit Duplikaten zu tun? h. das min oder max anstelle des Standards sum behalten?

+0

Ich bin mir ziemlich sicher, die Antwort ist nein, es gibt keine eingebaute Möglichkeit, das Verhalten für Duplikate zu ändern. Sie sollten jedoch die Verwendung von 'np.unique' nicht zu schnell verwerfen: Egal, wie groß Ihre Listen sind, scipy wird sie in Arrays umwandeln und ähnliche Operationen unter der Haube durchführen, also gibt es keinen Grund, warum Sie das tun sollte nicht versuchen. – Jaime

+1

'np.unique' ist 1d, daher erfordert die Handhabung dieser 2d-Koordinaten etwas zusätzlichen Aufwand. – hpaulj

+1

Wahr, aber Tricks wie [dies] (http://stackoverflow.com/questions/16970982/find-unique-rows-in-numpy-array) machen es 2D. –

Antwort

4

eine Zwischen dok Matrix Erstellen arbeitet in Ihrem Beispiel:

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) 

A coo Matrix setzt Ihre Eingabe-Arrays in seine data, col, row Attribute ohne Änderung. Die Summierung erfolgt erst, wenn sie in eine csc konvertiert wird.

todok lädt das Wörterbuch direkt aus den Attributen coo. Es schafft die leere dok Matrix und füllt es mit:

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

Also, wenn es doppelte (row,col) Werte, es ist das letzte, was bleibt. Dies verwendet das standardmäßige Python-Wörterbuch-Hashing, um die eindeutigen Schlüssel zu finden.


Hier ist ein Weg zur Verwendung np.unique. Ich musste ein spezielles Objekt-Array konstruieren, weil unique auf 1d operiert, und wir haben eine 2D-Indizierung.

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) 

Ich habe keine Ahnung, welcher Ansatz schneller ist.


Eine alternative Möglichkeit, den einzigartigen Index bekommen, wie pro 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 hat seine eigenen Daten zu besitzen, um die dtype mit Ansicht zu ändern, damit die .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

Sieht aus wie ein netter Trick. Ich kann es jetzt nicht versuchen, dauert es viel Zeit/Gedächtnis die Umwandlung zwischen Typen? –

+0

todok() ignoriert Dubletten bei scipy nicht 0.19 –

+0

Ja, 'coo.todok' enthält jetzt eine' self.sum_duplicates() 'Zeile. Die Lösung ist das Update wie ich es beschreibe, aber ohne diese "Summe". – hpaulj

Verwandte Themen