2010-07-14 17 views
39

Supongamos que tengo una 2d matriz dispersa. En mi verdadero caso de uso tanto en el número de filas y columnas son mucho más grandes (digamos, 20000 y 50000), por tanto, no puede caber en la memoria cuando se utiliza una representación densa:¿Cómo se multiplica por elementos una matriz scipy.sparse por una matriz 1d densa emitida?

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

Ahora supongamos que tengo una matriz 1d densa con toda componentes que no son ceros con un tamaño de 3 (o 50.000 en mi caso la vida real):

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

me gustaría para calcular la multiplicación elementwise de a y d usando la semántica de difusión habituales de numpy. Sin embargo, matrices dispersas en scipy son de la np.matrix: el operador '*' está sobrecargado para que se comporte como una matriz de multiplicación en lugar de la elementwise-multiplican:

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

Una solución sería hacer ' un' interruptor a la semántica de matriz para el operador '*', que daría el resultado esperado:

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

Pero no puede hacer eso ya que la llamada a toArray() se materializaría la versión densa de 'a' y no cabe en la memoria (y el resultado también será denso):

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

¿Alguna idea de cómo crear esto manteniendo solo las estructuras de datos dispersas y sin tener que hacer un ciclo de python ineficiente en las columnas de 'a'?

+0

Si 'd' es una matriz dispersa del mismo tamaño que' a' puede utilizar 'a.multiply (d)'. ¿Quizás puedas hacer una 'd' que tenga N filas de longitud y pasar por N filas de' a' a la vez? – mtrw

+1

Pero d es denso y no se puede emitir explícitamente en la memoria para satisfacer los requisitos de formas múltiples. Looping sobre un lote es una opción, pero me parece un poco hackish. Hubiera pensado que había una manera vainilla vectorizada/scipy de hacer esto sin un ciclo de Python. – ogrisel

+0

Supongo que el problema es que desea la representación de una matriz (dispersa) pero el funcionamiento mulitply de una matriz. Creo que vas a tener que tirar tu propia desafortunadamente. – mtrw

Respuesta

42

Respondí en scipy.org también, pero pensé que debería agregar una respuesta aquí, en caso de que otros encuentren esta página al buscar.

Puede convertir el vector en una matriz diagonal dispersa y luego usar la multiplicación de matrices (con *) para hacer lo mismo que la radiodifusión, pero de manera eficiente.

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

Hope that helps!

+0

Gracias, parece que va a resolver mi problema. – ogrisel

+0

Lo bueno de esto es que también funciona cuando 'X' es un' ndarray' o una matriz densa. +1. –

+4

Esto podría simplificarse aún más utilizando ['scipy.sparse.diags (d, 0)'] (http://docs.scipy.org/doc/scipy-0.16.1/reference/generated/scipy.sparse.diags. html) en lugar de 'lil_matrix' –

1

Bueno, aquí hay un código simple que hará lo que quieras. No sé si es tan eficiente como le gustaría, por lo tomas o lo dejas que:

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 

Sólo funciona con matrices lil por lo que tendrá que hacer algunos cambios si se quiere que funcione con otros formatos.

+0

gracias me hubiera gustado evitar los bucles en python sin embargo.Pero tal vez no hay forma de salir con las clases scipy.sparse actuales para este caso de uso. – ogrisel

23

Creo que A.multiply (B) debería funcionar en scipy sparse. El método multiplica multiplicación de "punto a punto", no multiplicación de matriz.

HTH

+1

El resultado es una matriz densa. No está bien. –

+3

@ K3 --- rnc el resultado es denso solo si B es denso. Si convierte B a cualquiera de los formatos dispersos, hará el truco. P.ej. A.multiply (csc_matrix (B)) – markhor

Cuestiones relacionadas