2010-07-14 14 views
39

Supponiamo di disporre di un array sparse 2d. Nel mio vero caso d'uso sia il numero di righe e colonne sono molto più grandi (diciamo 20000 e 50000) di conseguenza, non può andare bene in memoria quando viene utilizzata una rappresentazione densa:Come moltiplicare in modo elementare una matrice scipy.sparse con un array 1d denso trasmesso?

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

Ora supponiamo di avere un allineamento 1d fitta con tutta la componenti non-zeri di dimensione 3 (o 50000 nel mio caso reale vita):

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

desidero calcolare la moltiplicazione elementwise di a e d secondo i consueti semantica trasmissione di NumPy. Tuttavia, matrici sparse in SciPy sono del np.matrix: l'operatore '*' è sovraccaricato avere comportarsi come una matrice moltiplicare invece del elementwise-moltiplicano:

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

Una soluzione sarebbe quella di fare ' un' interruttore per la semantica di matrice per il '*' operatore, che avrebbe dato il risultato atteso:

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

Ma non può farlo in quanto la chiamata a ToArray() sarebbe materializzarsi la versione densa di 'a', che non si adatta alla memoria (e anche il risultato sarà denso):

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

Qualche idea su come costruire questo mantenendo solo le strutture dati sparse e senza dover fare un loop python non efficiente sulle colonne di 'a'?

+0

Se 'd' è una matrice sparsa della stessa dimensione come' a' è possibile utilizzare 'a.multiply (d)'. Forse puoi fare un 'd' che è N righe lunghe e passare su N righe di' a' alla volta? – mtrw

+1

Ma d è denso e non può essere trasmesso esplicitamente in memoria per soddisfare i requisiti di forma multipla. Fare un ciclo su un lotto è un'opzione ma trovo questo un po 'hackerato. Avrei pensato che esistesse un modo vanigliato/scipy per farlo senza un loop python. – ogrisel

+0

Immagino che il problema sia la rappresentazione di una matrice (sparsa) ma l'operazione multipla di un array. Penso che dovrai sfornare il tuo sfortunatamente. – mtrw

risposta

42

Ho risposto anche a scipy.org, ma ho pensato di aggiungere una risposta qui, nel caso in cui altri trovino questa pagina durante la ricerca.

È possibile trasformare il vettore in una matrice diagonale sparsa e quindi utilizzare la moltiplicazione della matrice (con *) per fare la stessa cosa della trasmissione, ma in modo efficiente.

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

Spero che questo aiuti!

+0

Grazie sembra che risolverà il mio problema. – ogrisel

+0

La cosa grandiosa di questo è che funziona anche quando 'X' è un' ndarray' o una densa matrice. +1. –

+4

Questo potrebbe essere ulteriormente semplificato usando ['scipy.sparse.diags (d, 0)'] (http://docs.scipy.org/doc/scipy-0.16.1/reference/generated/scipy.sparse.diags. html) piuttosto che 'lil_matrix' –

1

Bene, ecco un semplice codice che farà ciò che desideri. Non so se è così efficace come si vorrebbe, in modo da prendere o lasciare:

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 

Funziona solo con matrici lil quindi dovrete apportare alcune modifiche, se si desidera farlo funzionare con altri formati.

+0

tuttavia avrei preferito evitare i loop in python.Ma forse non esiste una via d'uscita con le attuali classi scipy.sparse per questo caso d'uso. – ogrisel

23

Penso che A.multiply (B) dovrebbe funzionare in scarse sparse. Il metodo si moltiplica moltiplicando "point-wise", non moltiplicando la matrice.

HTH

+1

Il risultato è una matrice densa. Non bene. –

+3

@ K3 --- rnc il risultato è denso solo se B è denso. Se converti B in uno qualsiasi dei formati sparsi, questo farà il trucco. Per esempio. A.multiply (csc_matrix (B)) – markhor

Problemi correlati