Cómo guardar diccionarios y matrices en el mismo archivo (con numpy.savez)

primera pregunta aquí Intentaré ser conciso.

Estoy generando múltiples arreglos que contienen información de características para una aplicación de aprendizaje automático. Como las matrices no tienen las mismas dimensiones, las almaceno en un diccionario en lugar de en una matriz. Hay dos tipos diferentes de características, así que estoy usando dos diccionarios diferentes.

También genero tags para ir con las características. Estas tags se almacenan en matrices. Además, hay cadenas que contienen los parámetros exactos utilizados para ejecutar el script y una marca de tiempo.

En general, se ve así:

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... } 

Ahora mi objective sería hacer esto:

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

Esto parece funcionar (es decir, un archivo de este tipo se guarda sin que se produzca un error y se puede cargar nuevamente). Sin embargo, cuando trato de cargar, por ejemplo, la característica del archivo de nuevo:

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

Luego, en lugar de recuperar un diccionario, obtengo una gran cantidad de formas (0) donde no sé cómo acceder a los contenidos:

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

También las cadenas se convierten en matrices y obtienen un tipo de datos extraño:

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

En resumen, asumo que esto no es como se hace correctamente. Sin embargo, preferiría no colocar todas las variables en un gran diccionario porque las recuperaré en otro proceso y me gustaría simplemente recorrer el archivo dictionary.keys () sin preocuparme por la comparación de cadenas.

Cualquier idea es muy apreciada. Gracias

Como @fraxel ya ha sugerido, usar pickle es una opción mucho mejor en este caso. Sólo guarda un dict con tus artículos en él.

Sin embargo, asegúrese de utilizar pickle con un protocolo binario. Por defecto, es un formato menos eficiente, lo que resultará en un uso excesivo de la memoria y en archivos enormes si sus arreglos son grandes.

 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) 

Dicho esto, echemos un vistazo a lo que sucede con más detalle con fines ilustrativos.

numpy.savez espera que cada elemento sea una matriz. De hecho, llama a np.asarray en todo lo que pasas.

Si convierte un dict en una matriz, obtendrá una matriz de objetos. P.ej

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

De manera similar, si crea una matriz a partir de una cadena, obtendrá una matriz de cadenas:

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

Sin embargo, debido a una peculiaridad en la forma en que se manejan las matrices de objetos, si pasa un solo objeto (en su caso, su dict ) que no es una tupla, lista o matriz, obtendrá un objeto de 0 dimensiones. formación.

Esto significa que no se puede indexar directamente. De hecho, haciendo testarr[0] elevará un IndexError . Los datos todavía están allí, pero primero debe agregar una dimensión, por lo que debe hacer yourdictionary = testarr.reshape(-1)[0] .

Si todo esto parece torpe, es porque lo es. Las matrices de objetos son esencialmente siempre la respuesta incorrecta. (Aunque podría decirse que asarray debería pasar ndmin=1 a array , lo que resolvería este problema en particular, pero potencialmente rompería otras cosas).

savez está diseñado para almacenar matrices, en lugar de objetos arbitrarios. Debido a la forma en que funciona, puede almacenar objetos completamente arbitrarios, pero no debe usarse de esa manera.

Sin embargo, si quisiera usarlo, una solución rápida sería:

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

Y luego tendrías acceso a las cosas con

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

Sin embargo, esto es claramente mucho más torpe que solo usar pickle. Use numpy.savez cuando solo esté guardando arrays. En este caso, está guardando estructuras de datos anidadas, no matrices.

Si necesita guardar sus datos de forma estructurada, debe considerar el uso del formato de archivo HDF5 ( http://www.hdfgroup.org/HDF5/ ). Es muy flexible, fácil de usar, eficiente y es posible que otro software ya lo admita (HDFView, Mathematica, Matlab, Origin …). Hay un enlace de python simple llamado h5py .

Puede almacenar conjuntos de datos en una estructura similar a un sistema de archivos y definir atributos para cada conjunto de datos, como un diccionario. Por ejemplo:

 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 lectura de los datos también es simple, incluso puede cargar unos pocos elementos de un archivo grande si desea:

 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"] 

Encontrará más funciones y posibilidades en la documentación y en los sitios web (la Guía de inicio rápido puede ser de interés).

Ponga todas sus variables en un objeto y luego use Pickle . Es una mejor manera de almacenar información del estado.