¿Cómo se guarda / carga un scipy sparse csr_matrix
en un formato portátil? La matriz dispersa scipy se crea en Python 3 (Windows de 64 bits) para ejecutarse en Python 2 (Linux de 64 bits). Inicialmente, usé pickle (con protocolo = 2 y fix_imports = True) pero esto no funcionó al pasar de Python 3.2.2 (Windows de 64 bits) a Python 2.7.2 (Windows de 32 bits) y obtuve el error:
TypeError: ('data type not understood', <built-in function _reconstruct>, (<type 'numpy.ndarray'>, (0,), '[98]')).
A continuación, intentó numpy.save
y numpy.load
al igual que scipy.io.mmwrite()
y scipy.io.mmread()
y ninguno de estos métodos funcionó bien.
Respuestas:
editar: SciPy 1.19 ahora tiene
scipy.sparse.save_npz
yscipy.sparse.load_npz
.from scipy import sparse sparse.save_npz("yourmatrix.npz", your_matrix) your_matrix_back = sparse.load_npz("yourmatrix.npz")
Para ambas funciones, el
file
argumento también puede ser un objeto similar a un archivo (es decir, el resultado deopen
) en lugar de un nombre de archivo.Recibí una respuesta del grupo de usuarios de Scipy:
Así por ejemplo:
def save_sparse_csr(filename, array): np.savez(filename, data=array.data, indices=array.indices, indptr=array.indptr, shape=array.shape) def load_sparse_csr(filename): loader = np.load(filename) return csr_matrix((loader['data'], loader['indices'], loader['indptr']), shape=loader['shape'])
fuente
if not filename.endswith('.npz'): filename += '.npz'
scipy.sparse.save_npz
yload
.Aunque escribe
scipy.io.mmwrite
yscipy.io.mmread
no funciona para usted, solo quiero agregar cómo funcionan. Esta pregunta es el no. 1 éxito de Google, así que yo mismo comencé connp.savez
ypickle.dump
antes de cambiar a las funciones scipy simples y obvias. Funcionan para mí y no deberían ser supervisados por aquellos que aún no los probaron.from scipy import sparse, io m = sparse.csr_matrix([[0,0,0],[1,0,0],[0,1,0]]) m # <3x3 sparse matrix of type '<type 'numpy.int64'>' with 2 stored elements in Compressed Sparse Row format> io.mmwrite("test.mtx", m) del m newm = io.mmread("test.mtx") newm # <3x3 sparse matrix of type '<type 'numpy.int32'>' with 2 stored elements in COOrdinate format> newm.tocsr() # <3x3 sparse matrix of type '<type 'numpy.int32'>' with 2 stored elements in Compressed Sparse Row format> newm.toarray() # array([[0, 0, 0], [1, 0, 0], [0, 1, 0]], dtype=int32)
fuente
import scipy
. Se necesita un explícitofrom scipy import io
oimport scipy.io
.np.savez
ycPickle
soluciones y productos ~ archivo más grande de 3x. Consulte mi respuesta para conocer los detalles de la prueba.Aquí hay una comparación de rendimiento de las tres respuestas más votadas usando el cuaderno Jupyter. La entrada es una matriz dispersa aleatoria de 1M x 100K con densidad 0.001, que contiene 100M de valores distintos de cero:
from scipy.sparse import random matrix = random(1000000, 100000, density=0.001, format='csr') matrix <1000000x100000 sparse matrix of type '<type 'numpy.float64'>' with 100000000 stored elements in Compressed Sparse Row format>
io.mmwrite
/io.mmread
from scipy.sparse import io %time io.mmwrite('test_io.mtx', matrix) CPU times: user 4min 37s, sys: 2.37 s, total: 4min 39s Wall time: 4min 39s %time matrix = io.mmread('test_io.mtx') CPU times: user 2min 41s, sys: 1.63 s, total: 2min 43s Wall time: 2min 43s matrix <1000000x100000 sparse matrix of type '<type 'numpy.float64'>' with 100000000 stored elements in COOrdinate format> Filesize: 3.0G.
(tenga en cuenta que el formato ha cambiado de csr a coo).
np.savez
/np.load
import numpy as np from scipy.sparse import csr_matrix def save_sparse_csr(filename, array): # note that .npz extension is added automatically np.savez(filename, data=array.data, indices=array.indices, indptr=array.indptr, shape=array.shape) def load_sparse_csr(filename): # here we need to add .npz extension manually loader = np.load(filename + '.npz') return csr_matrix((loader['data'], loader['indices'], loader['indptr']), shape=loader['shape']) %time save_sparse_csr('test_savez', matrix) CPU times: user 1.26 s, sys: 1.48 s, total: 2.74 s Wall time: 2.74 s %time matrix = load_sparse_csr('test_savez') CPU times: user 1.18 s, sys: 548 ms, total: 1.73 s Wall time: 1.73 s matrix <1000000x100000 sparse matrix of type '<type 'numpy.float64'>' with 100000000 stored elements in Compressed Sparse Row format> Filesize: 1.1G.
cPickle
import cPickle as pickle def save_pickle(matrix, filename): with open(filename, 'wb') as outfile: pickle.dump(matrix, outfile, pickle.HIGHEST_PROTOCOL) def load_pickle(filename): with open(filename, 'rb') as infile: matrix = pickle.load(infile) return matrix %time save_pickle(matrix, 'test_pickle.mtx') CPU times: user 260 ms, sys: 888 ms, total: 1.15 s Wall time: 1.15 s %time matrix = load_pickle('test_pickle.mtx') CPU times: user 376 ms, sys: 988 ms, total: 1.36 s Wall time: 1.37 s matrix <1000000x100000 sparse matrix of type '<type 'numpy.float64'>' with 100000000 stored elements in Compressed Sparse Row format> Filesize: 1.1G.
Nota : cPickle no funciona con objetos muy grandes (consulte esta respuesta ). En mi experiencia, no funcionó para una matriz de 2.7M x 50k con valores distintos de cero de 270M.
np.savez
La solución funcionó bien.Conclusión
(basado en esta prueba simple para matrices CSR)
cPickle
es el método más rápido, pero no funciona con matrices muy grandes,np.savez
es solo un poco más lento, mientras queio.mmwrite
es mucho más lento, produce archivos más grandes y restaura el formato incorrecto. También lonp.savez
es el ganador aquí.fuente
from scipy.sparse import io
no funciona. En su lugar, hazlofrom scipy import io
. Docsscipy
.Ahora puede usar
scipy.sparse.save_npz
: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.save_npz.htmlfuente
Suponiendo que tiene scipy en ambas máquinas, puede usar
pickle
.Sin embargo, asegúrese de especificar un protocolo binario al decapar matrices numpy. De lo contrario, terminará con un archivo enorme.
En cualquier caso, debería poder hacer esto:
import cPickle as pickle import numpy as np import scipy.sparse # Just for testing, let's make a dense array and convert it to a csr_matrix x = np.random.random((10,10)) x = scipy.sparse.csr_matrix(x) with open('test_sparse_array.dat', 'wb') as outfile: pickle.dump(x, outfile, pickle.HIGHEST_PROTOCOL)
Luego puede cargarlo con:
import cPickle as pickle with open('test_sparse_array.dat', 'rb') as infile: x = pickle.load(infile)
fuente
cPickle
no funciona con matrices muy grandes ( enlace ).A partir de scipy 0.19.0, puede guardar y cargar matrices dispersas de esta manera:
from scipy import sparse data = sparse.csr_matrix((3, 4)) #Save sparse.save_npz('data_sparse.npz', data) #Load data = sparse.load_npz("data_sparse.npz")
fuente
EDITAR Aparentemente, es bastante simple:
def sparse_matrix_tuples(m): yield from m.todok().items()
Lo que producirá
((i, j), value)
tuplas, que son fáciles de serializar y deserializar. No estoy seguro de cómo se compara el rendimiento con el código a continuacióncsr_matrix
, pero definitivamente es más simple. Dejo la respuesta original a continuación ya que espero que sea informativa.Agregando mis dos centavos: para mí,
npz
no es portátil ya que no puedo usarlo para exportar mi matriz fácilmente a clientes que no son de Python (por ejemplo, PostgreSQL, me alegro de que me corrijan). Así que me hubiera gustado obtener una salida CSV para la matriz dispersa (de forma muy similar a como la obtendría conprint()
la matriz dispersa). Cómo lograr esto depende de la representación de la matriz dispersa. Para una matriz CSR, el siguiente código escupe salida CSV. Puede adaptarse para otras representaciones.import numpy as np def csr_matrix_tuples(m): # not using unique will lag on empty elements uindptr, uindptr_i = np.unique(m.indptr, return_index=True) for i, (start_index, end_index) in zip(uindptr_i, zip(uindptr[:-1], uindptr[1:])): for j, data in zip(m.indices[start_index:end_index], m.data[start_index:end_index]): yield (i, j, data) for i, j, data in csr_matrix_tuples(my_csr_matrix): print(i, j, data, sep=',')
Es aproximadamente 2 veces más lento que
save_npz
en la implementación actual, por lo que he probado.fuente
Esto es lo que usé para salvar un
lil_matrix
.import numpy as np from scipy.sparse import lil_matrix def save_sparse_lil(filename, array): # use np.savez_compressed(..) for compression np.savez(filename, dtype=array.dtype.str, data=array.data, rows=array.rows, shape=array.shape) def load_sparse_lil(filename): loader = np.load(filename) result = lil_matrix(tuple(loader["shape"]), dtype=str(loader["dtype"])) result.data = loader["data"] result.rows = loader["rows"] return result
Debo decir que encontré np.load (..) de NumPy muy lento . Esta es mi solución actual, siento que funciona mucho más rápido:
from scipy.sparse import lil_matrix import numpy as np import json def lil_matrix_to_dict(myarray): result = { "dtype": myarray.dtype.str, "shape": myarray.shape, "data": myarray.data, "rows": myarray.rows } return result def lil_matrix_from_dict(mydict): result = lil_matrix(tuple(mydict["shape"]), dtype=mydict["dtype"]) result.data = np.array(mydict["data"]) result.rows = np.array(mydict["rows"]) return result def load_lil_matrix(filename): result = None with open(filename, "r", encoding="utf-8") as infile: mydict = json.load(infile) result = lil_matrix_from_dict(mydict) return result def save_lil_matrix(filename, myarray): with open(filename, "w", encoding="utf-8") as outfile: mydict = lil_matrix_to_dict(myarray) json.dump(mydict, outfile)
fuente
Esto funciona para mi:
import numpy as np import scipy.sparse as sp x = sp.csr_matrix([1,2,3]) y = sp.csr_matrix([2,3,4]) np.savez(file, x=x, y=y) npz = np.load(file) >>> npz['x'].tolist() <1x3 sparse matrix of type '<class 'numpy.int64'>' with 3 stored elements in Compressed Sparse Row format> >>> npz['x'].tolist().toarray() array([[1, 2, 3]], dtype=int64)
El truco consistía en llamar
.tolist()
para convertir la matriz de objetos de forma 0 en el objeto original.fuente
Se me pidió que enviara la matriz en un formato simple y genérico:
Terminé con esto:
def save_sparse_matrix(m,filename): thefile = open(filename, 'w') nonZeros = np.array(m.nonzero()) for entry in range(nonZeros.shape[1]): thefile.write("%s,%s,%s\n" % (nonZeros[0, entry], nonZeros[1, entry], m[nonZeros[0, entry], nonZeros[1, entry]]))
fuente