2011-01-14 16 views
26

Supongamos que tengo una matriz NxN M (lil_matrix o csr_matrix) de scipy.sparse, y quiero hacer que (N + 1) xN donde M_modified [i, j] = M [i, j] para 0 < = i < N (y todos j) y M [N, j] = 0 para todos j. Básicamente, quiero agregar una fila de ceros a la parte inferior de M y conservar el resto de la matriz. ¿Hay alguna manera de hacer esto sin copiar los datos?expandiendo (agregando una fila o columna) una matriz scipy.sparse

Respuesta

4

No creo que haya ninguna forma de escapar realmente de la copia. Ambos tipos de matrices dispersas almacenan sus datos como matrices Numpy (en los atributos de datos e índices para csr y en los atributos de datos y filas para lil) internamente y las matrices Numpy no se pueden extender.

actualización con más información:

LIL significa la sigla lista enlazada, pero la implementación actual no está a la altura de su nombre. Las matrices Numpy utilizadas para data y rows son ambas de tipo objeto. Cada uno de los objetos en estas matrices son en realidad listas de Python (una lista vacía cuando todos los valores son cero en una fila). Las listas de Python no son listas exactamente vinculadas, pero son bastante cercanas y, francamente, una mejor opción debido a la búsqueda O (1). Personalmente, no veo el punto de usar aquí una matriz de objetos Numpy en lugar de solo una lista de Python. Con bastante facilidad, podría cambiar la implementación de lil actual para usar listas de Python que le permitirían agregar una fila sin copiar toda la matriz.

+0

Si es lo suficientemente crítica para su aplicación, usted podría ser capaz de implementar una nueva clase con la interfaz scipy.sparse que utiliza un tipo de datos más fácilmente extensible bajo el capó. –

+1

Quizás alguien más conocedor de la estructura de datos subyacente pueda responder a esto. Pensé que lil_matrix se implementó con listas vinculadas? – RandomGuy

+0

@scandido, vea si mi última adición responde a su pregunta. –

8

No estoy seguro si aún está buscando una solución, pero quizás otros pueden consultar hstack y vstack - http://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.hstack.html. Creo que podemos definir un csr_matrix para la única fila adicional y luego vstack con la matriz anterior.

+0

[código fuente para vstack] (https://github.com/scipy/scipy/blob/v0.19.0/scipy/sparse/construct.py#L461-L492) Como esto implica, devuelve una nueva copia de la entrada matrices, por lo tanto, no es lo suficientemente eficiente si queremos expandir una matriz ** en el lugar **. – JenkinsY

24

Scipy no tiene una forma de hacer esto sin copiar los datos, pero puede hacerlo usted mismo cambiando los atributos que definen la matriz dispersa.

Hay 4 atributos que componen el csr_matrix:

datos: Una matriz que contiene los valores reales en la matriz

índices: Una matriz que contiene el índice de la columna correspondiente a cada valor de datos

indptr: una matriz que especifica el índice antes del primer valor en los datos para cada fila. Si la fila está vacía, el índice es el mismo que la columna anterior.

forma: Una tupla que contiene la forma de la matriz

Si sólo está añadiendo una fila de ceros hasta el fondo todo lo que tiene que hacer es cambiar la forma y indptr para su matriz.

x = np.ones((3,5)) 
x = csr_matrix(x) 
x.toarray() 
>> array([[ 1., 1., 1., 1., 1.], 
      [ 1., 1., 1., 1., 1.], 
      [ 1., 1., 1., 1., 1.]]) 
# reshape is not implemented for csr_matrix but you can cheat and do it yourself. 
x._shape = (4,5) 
# Update indptr to let it know we added a row with nothing in it. So just append the last 
# value in indptr to the end. 
# note that you are still copying the indptr array 
x.indptr = np.hstack((x.indptr,x.indptr[-1])) 
x.toarray() 
array([[ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 0., 0., 0., 0., 0.]]) 

Aquí está una función para manejar el caso más general de vstacking de cualquier 2 csr_matrices. Todavía terminas copiando las matrices numpy subyacentes, pero todavía es significativamente más rápido que el método scipy vstack.

def csr_vappend(a,b): 
    """ Takes in 2 csr_matrices and appends the second one to the bottom of the first one. 
    Much faster than scipy.sparse.vstack but assumes the type to be csr and overwrites 
    the first matrix instead of copying it. The data, indices, and indptr still get copied.""" 

    a.data = np.hstack((a.data,b.data)) 
    a.indices = np.hstack((a.indices,b.indices)) 
    a.indptr = np.hstack((a.indptr,(b.indptr + a.nnz)[1:])) 
    a._shape = (a.shape[0]+b.shape[0],b.shape[1]) 
    return a 
+1

Creo que puede salirse con la suya sin devolver 'a', ya que los argumentos de funciones se pasan por referencia,' a' se modifica directamente incluso dentro del alcance de la función. Además, ¿puede haber un análogo csc_happend (a, b)? – richizy

+0

Buena idea, simplemente restablecer la forma. – Jan

Cuestiones relacionadas