python - matrices - ¿Cómo se multiplica por elementos una matriz scipy.sparse por una matriz de 1d densa emitida?
sparse matrices python (3)
Supongamos que tengo una 2d matriz dispersa. En mi caso de uso real, tanto el número de filas como las columnas son mucho más grandes (digamos 20000 y 50000) por lo que no cabe en la memoria cuando se utiliza una representación densa:
>>> 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 todos los componentes que no son ceros con tamaño 3 (o 50000 en mi caso de la vida real):
>>> d = np.ones(3) * 3
>>> d
array([ 3., 3., 3.])
Me gustaría calcular la multiplicación por elementos de a y d usando la semántica de difusión habitual de numpy. Sin embargo, las matrices dispersas en scipy son de np.matrix: el operador ''*'' está sobrecargado para que se comporte como un multiplicador de matriz en lugar de multiplicar por elementos:
>>> a * d
array([ 0., -3., 0., 0., 6.])
Una solución sería hacer ''a'' cambiar 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 puedo hacer eso ya que la llamada a toarray () materializaría la versión densa de ''a'' que no cabe en la memoria (y el resultado también será denso):
>>> ssp.issparse(a.toarray())
False
¿Alguna idea de cómo construir esto manteniendo solo estructuras de datos dispersas y sin tener que hacer un ciclo de python no eficiente en las columnas de ''a''?
Bueno, aquí hay un código simple que hará lo que quieras. No sé si es tan eficiente como te gustaría, así que tómalo o déjalo:
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
Solo funciona con matrices lil, por lo que deberá realizar algunos cambios si desea que funcione con otros formatos.
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
También respondí en scipy.org, 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 matriz (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.]])
¡Espero que ayude!