Jak zapisać / załadować Scipy Sparse csr_matrix
w formacie przenośnym? Scipy Sparse matrix jest tworzona w Pythonie 3 (Windows 64-bitowy) do uruchamiania w Pythonie 2 (Linux 64-bitowy). Początkowo użyłem pickle (z protokołem = 2 i fix_imports = True), ale to nie zadziałało, przechodząc z Pythona 3.2.2 (Windows 64-bitowy) do Pythona 2.7.2 (Windows 32-bitowy) i otrzymałem błąd:
TypeError: ('data type not understood', <built-in function _reconstruct>, (<type 'numpy.ndarray'>, (0,), '[98]')).
Następnie wypróbowano numpy.save
i numpy.load
jak również scipy.io.mmwrite()
i scipy.io.mmread()
i żadna z tych metod też nie zadziałała.
Odpowiedzi:
edycja: SciPy 1.19 ma teraz
scipy.sparse.save_npz
iscipy.sparse.load_npz
.from scipy import sparse sparse.save_npz("yourmatrix.npz", your_matrix) your_matrix_back = sparse.load_npz("yourmatrix.npz")
W przypadku obu funkcji
file
argumentem może być również obiekt plikopodobny (tj. Wynikopen
) zamiast nazwy pliku.Mam odpowiedź od grupy użytkowników Scipy:
Na przykład:
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'])
źródło
if not filename.endswith('.npz'): filename += '.npz'
scipy.sparse.save_npz
iload
.Chociaż piszesz
scipy.io.mmwrite
iscipy.io.mmread
nie pracujesz dla Ciebie, chcę tylko dodać, jak one działają. To pytanie brzmi: nie. 1 trafienie w Google, więc sam zacząłem odnp.savez
ipickle.dump
przed przejściem do prostych i oczywistych funkcji scipy. Pracują dla mnie i nie powinny być nadzorowane przez tych, którzy jeszcze ich nie wypróbowali.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)
źródło
import scipy
. Jawnyfrom scipy import io
lubimport scipy.io
jest potrzebny.np.savez
icPickle
rozwiązań oraz produktów ~ 3x większy plik. Zobacz moją odpowiedź, aby poznać szczegóły testu.Oto porównanie wydajności trzech najbardziej pozytywnych odpowiedzi przy użyciu notebooka Jupyter. Dane wejściowe to losowa macierz rzadka 1M x 100K o gęstości 0,001, zawierająca 100M wartości niezerowych:
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.
(zwróć uwagę, że format został zmieniony z csr na 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.
Uwaga : cPickle nie działa z bardzo dużymi obiektami (zobacz tę odpowiedź ). Z mojego doświadczenia wynika, że nie działało to dla matrycy 2,7M x 50k z 270M wartościami niezerowymi.
np.savez
rozwiązanie działało dobrze.Wniosek
(oparty na tym prostym teście dla macierzy CSR)
cPickle
jest najszybszą metodą, ale nie działa z bardzo dużymi macierzami,np.savez
jest tylko trochę wolniejszy, podczas gdyio.mmwrite
jest znacznie wolniejszy, tworzy większy plik i przywraca zły format. Więcnp.savez
jest tutaj zwycięzcą.źródło
from scipy.sparse import io
nie działa. Zamiast tego po prostu zróbfrom scipy import io
. Dokumentyscipy
.Teraz możesz użyć
scipy.sparse.save_npz
: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.save_npz.htmlźródło
Zakładając, że masz scipy na obu komputerach, możesz po prostu użyć
pickle
.Jednak pamiętaj, aby określić protokół binarny podczas wytrawiania tablic numpy. W przeciwnym razie skończysz z ogromnym plikiem.
W każdym razie powinieneś móc to zrobić:
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)
Następnie możesz załadować go za pomocą:
import cPickle as pickle with open('test_sparse_array.dat', 'rb') as infile: x = pickle.load(infile)
źródło
cPickle
nie działa z bardzo dużymi matrycami ( link ).Począwszy od scipy 0.19.0, możesz zapisywać i ładować rzadkie macierze w ten sposób:
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")
źródło
EDYCJA Najwyraźniej wystarczy:
def sparse_matrix_tuples(m): yield from m.todok().items()
Który da
((i, j), value)
krotki, które można łatwo serializować i deserializować. Nie jestem pewien, jak wypada pod względem wydajności w porównaniu z poniższym kodemcsr_matrix
, ale jest zdecydowanie prostszy. Zostawiam oryginalną odpowiedź poniżej, ponieważ mam nadzieję, że jest pouczająca.Dodanie moich dwóch centów: dla mnie
npz
nie jest przenośne, ponieważ nie mogę go użyć do łatwego eksportu mojej macierzy do klientów innych niż Python (np. PostgreSQL - cieszę się, że zostałem poprawiony). Więc chciałbym uzyskać wyjście CSV dla rzadkiej macierzy (podobnie jak wprint()
przypadku rzadkiej macierzy). Sposób osiągnięcia tego zależy od reprezentacji rzadkiej macierzy. W przypadku macierzy CSR poniższy kod wypluwa dane wyjściowe w formacie CSV. Możesz dostosować się do innych reprezentacji.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=',')
Jest około 2 razy wolniej niż
save_npz
w obecnej implementacji, z tego co testowałem.źródło
To jest to, czego użyłem do zapisania pliku
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
Muszę powiedzieć, że np.load (..) NumPy jest bardzo powolny . To jest moje obecne rozwiązanie, czuję, że działa znacznie szybciej:
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)
źródło
To działa dla mnie:
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)
Sztuczka polegała na wywołaniu
.tolist()
konwersji tablicy obiektów shape 0 na oryginalny obiekt.źródło
Poproszono mnie o przesłanie matrycy w prostym i ogólnym formacie:
Skończyło się na tym:
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]]))
źródło