2011-06-08 22 views
9

Estoy intentando cargar una matriz dispersa que he guardado previamente. Guardar la matriz dispersa fue bastante fácil. Tratar de leerlo es un dolor. scipy.load devuelve una matriz 0d alrededor de mi matriz dispersa.Cargar matriz dispersa desde el archivo npy

import scipy as sp 
A = sp.load("my_array"); A 
array(<325729x325729 sparse matrix of type '<type 'numpy.int8'>' 
with 1497134 stored elements in Compressed Sparse Row format>, dtype=object) 

el fin de obtener una matriz dispersa tengo para aplanar la matriz 0d o utilice sp.asarray (A). Esto parece una forma realmente difícil de hacer las cosas. ¿Es Scipy lo suficientemente inteligente como para entender que ha cargado una matriz dispersa? ¿Hay una mejor manera de cargar una matriz dispersa?

Respuesta

13

Las funciones mmwrite/mmread en scipy.io pueden guardar/cargar matrices dispersas en el formato Matrix Market.

scipy.io.mmwrite('/tmp/my_array',x) 
scipy.io.mmread('/tmp/my_array').tolil()  

mmwrite y mmread puede ser todo lo que necesita. Está bien probado y utiliza un formato bien conocido.

Sin embargo, el siguiente podría ser un poco más rápido:

Podemos salvar las las coordenadas de fila y columna y los datos como matrices 1-d en formato NPZ.

import random 
import scipy.sparse as sparse 
import scipy.io 
import numpy as np 

def save_sparse_matrix(filename,x): 
    x_coo=x.tocoo() 
    row=x_coo.row 
    col=x_coo.col 
    data=x_coo.data 
    shape=x_coo.shape 
    np.savez(filename,row=row,col=col,data=data,shape=shape) 

def load_sparse_matrix(filename): 
    y=np.load(filename) 
    z=sparse.coo_matrix((y['data'],(y['row'],y['col'])),shape=y['shape']) 
    return z 

N=20000 
x = sparse.lil_matrix((N,N)) 
for i in xrange(N): 
    x[random.randint(0,N-1),random.randint(0,N-1)]=random.randint(1,100) 

save_sparse_matrix('/tmp/my_array',x) 
load_sparse_matrix('/tmp/my_array.npz').tolil() 

Aquí hay un código que sugiere guardar la matriz dispersa en un archivo de NPZ puede ser más rápido que el uso de mmwrite/mmread:

def using_np_savez():  
    save_sparse_matrix('/tmp/my_array',x) 
    return load_sparse_matrix('/tmp/my_array.npz').tolil() 

def using_mm(): 
    scipy.io.mmwrite('/tmp/my_array',x) 
    return scipy.io.mmread('/tmp/my_array').tolil()  

if __name__=='__main__': 
    for func in (using_np_savez,using_mm): 
     y=func() 
     print(repr(y)) 
     assert(x.shape==y.shape) 
     assert(x.dtype==y.dtype) 
     assert(x.__class__==y.__class__)  
     assert(np.allclose(x.todense(),y.todense())) 

rendimientos

% python -mtimeit -s'import test' 'test.using_mm()' 
10 loops, best of 3: 380 msec per loop 

% python -mtimeit -s'import test' 'test.using_np_savez()' 
10 loops, best of 3: 116 msec per loop 
+1

+1, 'scipy.io' es la solución adecuada. Yo agregaría que si quieres ir por el camino de la optimización, podrías considerar 'numpy.load (mmap_mode = 'r'/'c')'. La asignación de memoria de los archivos del disco proporciona una carga instantánea ** y ** puede ahorrar memoria, ya que la misma matriz mapeada en memoria se puede compartir en múltiples procesos. – Radim

+0

scipy.io.savemat es probablemente el mejor – mathtick

+0

Usar np_savez en vez de mm disminuyó el tiempo de carga de una gran matriz dispersa de 8min47 a 3s. Gracias ! También probé savez_compressed pero el tamaño es el mismo y el tiempo de carga mucho más largo. – MatthieuBizien

4

Uno puede extraer el objeto escondido en la matriz 0d usando() como índice:

A = sp.load("my_array")[()] 

Esto se ve raro, pero parece funcionar de todos modos, y es una solución muy breve.

+0

Estoy bastante seguro de que también puedes usar .item(), pero no me cites sobre eso :) – David

0

Para todos los votos de la respuesta mmwrite, me sorprende que nadie haya intentado responder la pregunta real. Pero como se ha reactivado, lo intentaré.

Esto reproduce el caso OP:

In [90]: x=sparse.csr_matrix(np.arange(10).reshape(2,5)) 
In [91]: np.save('save_sparse.npy',x) 
In [92]: X=np.load('save_sparse.npy') 
In [95]: X 
Out[95]: 
array(<2x5 sparse matrix of type '<type 'numpy.int32'>' 
    with 9 stored elements in Compressed Sparse Row format>, dtype=object) 
In [96]: X[()].A 
Out[96]: 
array([[0, 1, 2, 3, 4], 
     [5, 6, 7, 8, 9]]) 

In [93]: X[()].A 
Out[93]: 
array([[0, 1, 2, 3, 4], 
     [5, 6, 7, 8, 9]]) 
In [94]: x 
Out[94]: 
<2x5 sparse matrix of type '<type 'numpy.int32'>' 
    with 9 stored elements in Compressed Sparse Row format 

El [()] que `user4713166 dio nosotros no es un 'camino difícil' para extraer la matriz dispersa.

np.save y np.load están diseñados para funcionar en ndarrays. Pero una matriz dispersa no es una matriz, ni es una subclase (como es np.matrix). Parece que np.save envuelve el objeto que no es de matriz en un object dtype array y lo guarda junto con una forma del objeto en escabeche.

Cuando intento para salvar a un tipo diferente de objeto, una que no puede ser conservado en vinagre, me sale un mensaje de error en:

403 # We contain Python objects so we cannot write out the data directly. 
404 # Instead, we will pickle it out with version 2 of the pickle protocol. 

-> 405 pickle.dump (array, fp, el protocolo = 2)

Respondiendo a Is Scipy smart enough to understand that it has loaded a sparse array?, no. np.load no sabe acerca de las matrices dispersas.Pero np.save es lo suficientemente inteligente para despejar cuando se le da algo que no es una matriz, y np.load hace lo que puede con lo que encuentra en el archivo.

En cuanto a los métodos alternativos para guardar y cargar matrices dispersas, se ha mencionado el io.savemat, método compatible con MATLAB. Sería mi primera elección. Pero este ejemplo también muestra que puede usar el Python pickling normal. Eso podría ser mejor si necesita guardar un formato disperso particular. Y np.save no está mal si puede vivir con el paso de extracción [()]. :)


https://github.com/scipy/scipy/blob/master/scipy/io/matlab/mio5.py write_sparse - escasa se guardan en formato csc. Junto con los encabezados guarda A.indices.astype('i4')), A.indptr.astype('i4')), A.data.real y opcionalmente A.data.imag.


En las pruebas rápidas encuentro que np.save/load maneja todos los formatos escasas, excepto dok, donde el load se queja de una falta shape. De lo contrario, no encontraré ningún código de decapado especial en los archivos dispersos.

Cuestiones relacionadas