Suma sobre filas en scipy.sparse.csr_matrix

Tengo un csr_matrix grande y quiero agregar filas y obtener un nuevo csr_matrix con el mismo número de columnas pero con un número reducido de filas. (Contexto: la matriz es una matriz de término de documento obtenida de sklearn CountVectorizer y quiero poder combinar rápidamente los documentos de acuerdo con los códigos asociados con estos documentos)

Para un ejemplo mínimo, esta es mi matriz:

import numpy as np from scipy.sparse import csr_matrix from scipy.sparse import vstack row = np.array([0, 4, 1, 3, 2]) col = np.array([0, 2, 2, 0, 1]) dat = np.array([1, 2, 3, 4, 5]) A = csr_matrix((dat, (row, col)), shape=(5, 5)) print A.toarray() [[1 0 0 0 0] [0 0 3 0 0] [0 5 0 0 0] [4 0 0 0 0] [0 0 2 0 0]] 

No, digamos que quiero una nueva matriz B en la que las filas (1, 4) y (2, 3, 5) se combinen sumándolas, lo que se vería así:

 [[5 0 0 0 0] [0 5 5 0 0]] 

Y debería estar nuevamente en formato disperso (porque los datos reales con los que estoy trabajando son grandes). Intenté sumr rebanadas de la matriz y luego astackrla:

 idx1 = [1, 4] idx2 = [2, 3, 5] A_sub1 = A[idx1, :].sum(axis=1) A_sub2 = A[idx2, :].sum(axis=1) B = vstack((A_sub1, A_sub2)) 

Pero esto me da los valores resumidos solo para las columnas que no son cero en el sector, por lo que no puedo combinarlo con los otros sectores porque el número de columnas en los sectores sumdos es diferente.

Siento que debe haber una manera fácil de hacer esto. Pero no pude encontrar ninguna discusión de esto en línea o en la documentación. ¿Qué me estoy perdiendo?

Gracias por tu ayuda

Tenga en cuenta que puede hacer esto construyendo cuidadosamente otra matriz. Así es como funcionaría para una matriz densa:

 >>> S = np.array([[1, 0, 0, 1, 0,], [0, 1, 1, 0, 1]]) >>> np.dot(S, A.toarray()) array([[5, 0, 0, 0, 0], [0, 5, 5, 0, 0]]) >>> 

La versión dispersa es solo un poco más complicada. La información sobre qué filas se deben sumr se codifica en row :

 col = range(5) row = [0, 1, 1, 0, 1] dat = [1, 1, 1, 1, 1] S = csr_matrix((dat, (row, col)), shape=(2, 5)) result = S * A # check that the result is another sparse matrix print type(result) # check that the values are the ones we want print result.toarray() 

Salida:

  [[5 0 0 0 0] [0 5 5 0 0]] 

Puede manejar más filas en su salida incluyendo valores más altos en la row y extendiendo la forma de S consecuencia.

La indexación debe ser:

 idx1 = [0, 3] # rows 1 and 4 idx2 = [1, 2, 4] # rows 2,3 and 5 

Entonces necesitas mantener A_sub1 y A_sub2 en formato disperso y usar axis=0 :

 A_sub1 = csr_matrix(A[idx1, :].sum(axis=0)) A_sub2 = csr_matrix(A[idx2, :].sum(axis=0)) B = vstack((A_sub1, A_sub2)) B.toarray() array([[5, 0, 0, 0, 0], [0, 5, 5, 0, 0]]) 

Tenga en cuenta que creo que las operaciones A[idx, :].sum(axis=0) implican la conversión de matrices dispersas, por lo que la respuesta de @ Mr_E es probablemente mejor.

Alternativamente, funciona cuando usas axis=0 y np.vstack (a diferencia de scipy.sparse.vstack ):

 A_sub1 = A[idx1, :].sum(axis=0) A_sub2 = A[idx2, :].sum(axis=0) np.vstack((A_sub1, A_sub2)) 

Dando

 matrix([[5, 0, 0, 0, 0], [0, 5, 5, 0, 0]])