2012-04-09 15 views
11

prima domanda qui. Cercherò di essere conciso.Come salvare dizionari e array nello stesso archivio (con numpy.savez)

Sto generando più array contenenti informazioni sulle funzionalità per un'applicazione di apprendimento automatico. Poiché gli array non hanno dimensioni uguali, li memorizzo in un dizionario piuttosto che in un array. Ci sono due diversi tipi di funzionalità, quindi sto usando due dizionari diversi.

Genero anche etichette con le caratteristiche. Queste etichette sono memorizzate in array. Inoltre, ci sono stringhe contenenti i parametri esatti utilizzati per l'esecuzione dello script e un timestamp.

Tutto sommato sembra che questo:

import numpy as np  

feature1 = {} 
feature2 = {} 
label1 = np.array([]) 
label2 = np.array([]) 
docString = 'Commands passed to the script were...' 

# features look like this: 
feature1 = {'case 1': np.array([1, 2, 3, ...]), 
      'case 2': np.array([2, 1, 3, ...]), 
      'case 3': np.array([2, 3, 1, ...]), 
      and so on... } 

Ora il mio obiettivo sarebbe quello di fare questo:

np.savez(outputFile, 
     saveFeature1 = feature1, 
     saveFeature2 = feature2, 
     saveLabel1 = label1, 
     saveLabel2 = label2, 
     saveString = docString) 

Questo funziona apparentemente (vale a dire un tale file viene salvato con nessun errore gettato e può essere caricato di nuovo). Tuttavia, quando provo a caricare ad esempio la funzione dal file di nuovo:

loadedArchive = np.load(outFile) 
loadedFeature1 = loadedArchive['saveFeature1'] 
loadedString = loadedArchive['saveString'] 

Poi invece di ottenere un dizionario di nuovo, ho una serie NumPy di ​​forma (0), dove non so come accedere il contenuto:

In []: loadedFeature1 
Out[]: 
     array({'case 1': array([1, 2, 3, ...]), 
       'case 2': array([2, 3, 1, ...]), 
       ..., }, dtype=object) 

anche stringhe diventano matrici e ottenere uno strano tipo di dati:

In []: loadedString.dtype 
Out[]: dtype('|S20') 

Così, in breve, io parto dal presupposto che non è come è fatto correttamente. Tuttavia preferirei non mettere tutte le variabili in un unico grande dizionario perché le recupererò in un altro processo e vorrei semplicemente ripetere il ciclo su dictionary.keys() senza preoccuparmi del confronto tra stringhe.

Tutte le idee sono molto apprezzate. Grazie

risposta

15

Come già suggerito da @fraxel, l'utilizzo di pickle è un'opzione molto migliore in questo caso. Basta salvare uno dict con i tuoi articoli in esso.

Tuttavia, assicurarsi di utilizzare pickle con un protocollo binario. Per impostazione predefinita, il formato meno efficiente, che si tradurrà in un uso eccessivo della memoria e file enormi se gli array sono grandi.

saved_data = dict(outputFile, 
        saveFeature1 = feature1, 
        saveFeature2 = feature2, 
        saveLabel1 = label1, 
        saveLabel2 = label2, 
        saveString = docString) 

with open('test.dat', 'wb') as outfile: 
    pickle.dump(saved_data, outfile, protocol=pickle.HIGHEST_PROTOCOL) 

Ciò detto, diamo un'occhiata a ciò che sta accadendo in modo più dettagliato a scopo illustrativo.

numpy.savez si aspetta che ogni articolo sia un array. Infatti, chiama np.asarray su tutto ciò che si passa.

Se si trasforma un dict in un array, si otterrà un array di oggetti. Per esempio.

import numpy as np 

test = {'a':np.arange(10), 'b':np.arange(20)} 
testarr = np.asarray(test) 

Allo stesso modo, se si effettua una matrice di una stringa, si otterrà un array di stringhe:

In [1]: np.asarray('abc') 
Out[1]: 
array('abc', 
     dtype='|S3') 

Tuttavia, a causa di un cavillo nel modo in cui vengono gestite le matrici di oggetti, se si passare in un singolo oggetto (nel tuo caso, il tuo dict) che non è una tupla, lista o array, otterrai una matrice di oggetti 0-dimensionale.

Ciò significa che non è possibile indicizzarlo direttamente. Infatti, facendo testarr[0] si alza un IndexError. I dati sono ancora lì, ma devi prima aggiungere una dimensione, quindi devi fare yourdictionary = testarr.reshape(-1)[0].

Se tutto ciò sembra goffo, è perché lo è. Gli array di oggetti sono essenzialmente sempre la risposta sbagliata. (Anche se asarray dovrebbe passare probabilmente in ndmin=1 a array, che risolverebbe il problema particolare, ma potenzialmente interrompere altre cose.)

savez destinato a memorizzare array, piuttosto che oggetti arbitrari. A causa del modo in cui funziona, lo può memorizzare oggetti completamente arbitrari, ma non dovrebbe essere utilizzato in questo modo.

Se avete voglia di usarlo, però, una soluzione rapida sarebbe quella di fare:

np.savez(outputFile, 
     saveFeature1 = [feature1], 
     saveFeature2 = [feature2], 
     saveLabel1 = [label1], 
     saveLabel2 = [label2], 
     saveString = docString) 

e si sarebbe poi accedere le cose con

loadedArchive = np.load(outFile) 
loadedFeature1 = loadedArchive['saveFeature1'][0] 
loadedString = str(loadedArchive['saveString']) 

Tuttavia, questo è chiaramente molto più goffo che usare solo sottaceti. Usa numpy.savez quando stai salvando solo gli array. In questo caso, stai salvando strutture dati nidificate, non array.

+0

fantastico! grazie! – surchs

+2

Preferisco accedere all'elemento in un array '' '-a forma di' testarr.flat [0] '. Per il lettore curioso, è anche possibile usare una tupla vuota come in 'testarr [()]', ma questo fa male la leggibilità. –

0

Inserire tutte le variabili in un oggetto e quindi utilizzare Pickle. È un modo migliore per memorizzare le informazioni di stato.

+0

Grazie. Ma questo non significa che dovrò usare sempre lo stesso numero di variabili? Se, per qualche ragione, salverei solo un dizionario, allora ogni script che carica questo file con pickle rovinerebbe l'ordine delle variabili memorizzate. – surchs

+0

Pickle non funziona per questo in 2.x; nessun supporto a 64 bit. – Will

10

Se è necessario salvare i dati in modo strutturato, è consigliabile utilizzare il formato di file HDF5 (http://www.hdfgroup.org/HDF5/). È molto flessibile, facile da usare, efficiente e altri software potrebbero già supportarlo (HDFView, Mathematica, Matlab, Origin ..). Esiste un semplice collegamento Python chiamato h5py.

È possibile memorizzare set di dati in una struttura simile a un file system e definire attributi per ciascun set di dati, come un dizionario. Per esempio:

import numpy as np 
import h5py 

# some data 
table1 = np.array([(1,1), (2,2), (3,3)], dtype=[('x', float), ('y', float)]) 
table2 = np.ones(shape=(3,3)) 

# save to data to file 
h5file = h5py.File("test.h5", "w") 
h5file.create_dataset("Table1", data=table1) 
h5file.create_dataset("Table2", data=table2, compression=True) 
# add attributes 
h5file["Table2"].attrs["attribute1"] = "some info" 
h5file["Table2"].attrs["attribute2"] = 42 
h5file.close() 

la lettura dei dati è anche semplice, si può anche caricare solo alcuni elementi da un file di grandi dimensioni, se si desidera:

h5file = h5py.File("test.h5", "r") 
# read from file (numpy-like behavior) 
print h5file["Table1"]["x"][:2] 
# read everything into memory (real numpy array) 
print np.array(h5file["Table2"]) 
# read attributes 
print h5file["Table2"].attrs["attribute1"] 

più funzioni e possibilità si trovano nella documentazione e sui siti web (il Quick Start Guide potrebbe essere di interesse).

Problemi correlati