2010-07-14 9 views
39

Angenommen, ich habe ein 2d Sparse-Array. In meiner realen usecase sowohl die Anzahl der Zeilen und Spalten sind viel größer (etwa 20000 und 50000) kann daher nicht in dem Speicher passen, wenn eine dichte Darstellung verwendet wird:Wie man eine scipy.sparse-Matrix elementweise mit einem gesendeten dichten 1d-Array multipliziert?

>>> import numpy as np 
>>> import scipy.sparse as ssp 

>>> a = ssp.lil_matrix((5, 3)) 
>>> a[1, 2] = -1 
>>> a[4, 1] = 2 
>>> a.todense() 
matrix([[ 0., 0., 0.], 
     [ 0., 0., -1.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 2., 0.]]) 

Jetzt nimmt ich einen dichten 1d Array mit allen nicht-Nullen-Komponenten mit einer Größe von 3 (oder 50000 in meinem wirklichen Leben Fall):

>>> d = np.ones(3) * 3 
>>> d 
array([ 3., 3., 3.]) 

ich mag das element Multiplikation von a berechnen, und d die üblichen Sende Semantik von numpy verwenden. Jedoch schwach besetzte Matrizen in scipy sind der np.matrix: der ‚*‘ Operator überlastet ist, um es wie eine Matrix-Multiplikation verhalten zu haben, anstatt die elemente multiplizieren:

>>> a * d 
array([ 0., -3., 0., 0., 6.]) 

Eine Lösung wäre, zu machen " ein‘Schalter auf die Array-Semantik für den‚*‘Operator, das wäre das erwartete Ergebnis geben:

>>> a.toarray() * d 
array([[ 0., 0., 0.], 
     [ 0., 0., -3.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 6., 0.]]) 

Aber ich kann das nicht tun, da der Anruf(), um toArray die dichte Version materialisieren würde‚a‘die passt nicht in den Speicher (und das Ergebnis wird auch dicht):

>>> ssp.issparse(a.toarray()) 
False 

Haben Sie eine Idee, wie Sie dies erstellen können, während Sie nur wenig Datenstrukturen speichern und keine uneffiziente Python-Schleife für die Spalten von 'a' erstellen müssen?

+0

Wenn 'd' eine spärliche Matrix mit der gleichen Größe wie' a' Sie können 'verwenden a.multiply (d)'. Vielleicht kannst du ein "d" machen, das N Zeilen lang ist und über N Reihen von 'a' gleichzeitig kreisen? – mtrw

+1

Aber d ist dicht und kann nicht explizit im Speicher übertragen werden, um die Anforderungen an die Mehrfachform zu erfüllen. Schleifen über eine Charge ist eine Option, aber ich finde das ein bisschen hackish. Ich hätte gedacht, dass es eine vektorisierte/scipy Vanilleart gab, ohne eine Pythonschleife zu tun. – ogrisel

+0

Ich vermute, das Problem ist, dass Sie die Darstellung einer (spärlichen) Matrix wollen, aber die multiple Operation eines Arrays. Ich denke, dass du dich leider selbst rollen musst. – mtrw

Antwort

42

Ich antwortete auch auf scipy.org, aber ich dachte, ich sollte hier eine Antwort hinzufügen, falls andere diese Seite bei der Suche finden.

Sie können den Vektor in eine spärliche Diagonalmatrix umwandeln und dann die Matrixmultiplikation (mit *) verwenden, um das Gleiche wie das Senden zu tun, aber effizient.

>>> d = ssp.lil_matrix((3,3)) 
>>> d.setdiag(np.ones(3)*3) 
>>> a*d 
<5x3 sparse matrix of type '<type 'numpy.float64'>' 
with 2 stored elements in Compressed Sparse Row format> 
>>> (a*d).todense() 
matrix([[ 0., 0., 0.], 
     [ 0., 0., -3.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 6., 0.]]) 

Hoffe, dass hilft!

+0

Danke, es sieht so aus, als würde es mein Problem lösen. – ogrisel

+0

Das Tolle daran ist, dass es auch funktioniert, wenn 'X' ein' ndarray' oder eine dichte Matrix ist. +1. –

+4

Dies könnte mit ['scipy.sparse.diags (d, 0)'] (http://docs.scipy.org/doc/scipy-0.16.1/reference/generated/scipy.sparse.diags) weiter vereinfacht werden. html) statt "lil_matrix" –

1

Nun, hier ist ein einfacher Code, der tun wird, was Sie wollen. Ich weiß nicht, ob es so effizient ist, wie Sie möchten, so nehmen Sie es oder lassen Sie es:

import scipy.sparse as ssp 
def pointmult(a,b): 
    x = a.copy() 
    for i in xrange(a.shape[0]): 
     if x.data[i]: 
      for j in xrange(len(x.data[i])): 
       x.data[i] *= b[x.rows[i]] 
    return x 

Es funktioniert nur mit lil Matrizen, so dass Sie einige Änderungen vornehmen müssen, werden, wenn Sie es wollen arbeiten mit anderen Formaten.

+0

danke ich hätte aber gern for-loops in python vermieden.Aber vielleicht gibt es keinen Ausweg mit den aktuellen scipy.sparse-Klassen für diesen Anwendungsfall. – ogrisel

23

Ich denke, A.multiply (B) sollte in scipy spärlich arbeiten. Die Methode multipliziert "punktweise" Multiplikation, nicht Matrixmultiplikation.

HTH

+1

Das Ergebnis ist eine dichte Matrix. Nicht gut. –

+3

@ K3 --- rnc das Ergebnis ist nur dann dicht, wenn B dicht ist. Wenn Sie B in eines der Sparse-Formate konvertieren, ist das der Fall. Z.B. A.mehrfach (csc_matrix (B)) – markhor

Verwandte Themen