2011-06-08 13 views
9

Sto provando a caricare un array sparse che ho precedentemente salvato. Salvare l'array sparse era abbastanza facile. Cercare di leggerlo è un dolore. scipy.load restituisce un array 0d attorno al mio array sparse.Carica array sparse dal file 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) 

Al fine di ottenere una matrice sparsa devo appiattire la matrice 0d o usare sp.asarray (A). Questo sembra un modo davvero difficile per fare le cose. Scipy è abbastanza intelligente da capire che ha caricato un array sparse? C'è un modo migliore per caricare un array sparse?

risposta

13

Le funzioni mmwrite/mmread in scipy.io possono salvare/caricare matrici sparse nel formato Matrix Market.

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

mmwrite e mmread può essere tutto ciò che serve. È ben testato e utilizza un formato ben noto.

Tuttavia, la seguente potrebbe essere un po 'più veloce:

Possiamo salvare le coordinate di riga e di colonna e dati come 1-d array in 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() 

Ecco il codice che suggerisce il salvataggio del matrice sparsa in un file NPZ può essere più veloce rispetto all'utilizzo di 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())) 

rendimenti

% 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' è la soluzione corretta. Vorrei aggiungere che se si vuole andare giù per la strada di ottimizzazione, si potrebbe prendere in considerazione 'numpy.load (mmap_mode = 'r'/'c')'. La mappatura della memoria dei file dal disco fornisce un carico istantaneo ** e ** può risparmiare memoria, poiché la stessa matrice mappata sulla memoria può essere condivisa tra più processi. – Radim

+0

scipy.io.savemat è probabilmente il migliore – mathtick

+0

L'utilizzo di np_savez invece di mm ha ridotto il tempo di caricamento di una matrice sparsa di grandi dimensioni da 8 minuti a 3 secondi! Grazie ! Ho anche provato savez_compressed ma la dimensione è la stessa e il tempo di caricamento è molto più lungo. – MatthieuBizien

4

Si può estrarre il oggetto nascosto nell'array 0d usando() come indice:

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

Questo sembra strano, ma sembra funzionare comunque, ed è una soluzione molto breve.

+0

Sono abbastanza sicuro che tu possa usare anche .item(), ma non citarlo su quello :) – David

0

Per tutti i voti superiori della risposta mmwrite, sono sorpreso che nessuno abbia cercato di rispondere alla domanda. Ma dal momento che è stato riattivato, farò un tentativo.

Questo riproduce il 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 

Il [()] che `user4713166 ci ha dato non è un 'senso duro' per estrarre il matrice sparsa.

np.save e np.load sono progettati per funzionare su ndarrays. Ma una matrice sparsa non è un array di questo tipo, né è una sottoclasse (come è np.matrix). Sembra che np.save avvolga l'oggetto non-array in un object dtype array e lo salvi insieme a un modulo decapitato dell'oggetto.

Quando si tenta di salvare un diverso tipo di oggetto, uno che non può essere in salamoia, ricevo un messaggio di errore:

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, protocollo = 2)

Quindi in risposta a Is Scipy smart enough to understand that it has loaded a sparse array?, n. np.load non sa di array sparsi.Ma np.save è abbastanza intelligente per punt quando viene dato qualcosa che non è un array, e np.load fa quello che può con cosa se trova nel file.

Per quanto riguarda i metodi alternativi di salvataggio e caricamento di array sparsi, è stato menzionato il metodo io.savemat, MATLAB compatibile. Sarebbe la mia prima scelta Ma questo esempio mostra anche che puoi usare il normale Python pickling. Potrebbe essere meglio se hai bisogno di salvare un particolare formato sparso. E np.save non è male se puoi vivere con il passo di estrazione [()]. :)


https://github.com/scipy/scipy/blob/master/scipy/io/matlab/mio5.py write_sparse - sparse vengono salvati in formato csc. Insieme alle intestazioni salva A.indices.astype('i4')), A.indptr.astype('i4')), A.data.real e facoltativamente A.data.imag.


Nei test rapidi trovo che np.save/load gestisce tutti i formati sparse, tranne dok, dove il load lamenta la mancanza di un shape. Altrimenti non trovo alcun codice speciale di decapaggio nei file sparsi.