¿Cómo guardar y cargar datos numpy.array () correctamente?

104

Me pregunto cómo guardar y cargar numpy.arraydatos correctamente. Actualmente estoy usando el numpy.savetxt()método. Por ejemplo, si tengo una matriz markers, que se ve así:

ingrese la descripción de la imagen aquí

Intento salvarlo mediante el uso de:

numpy.savetxt('markers.txt', markers)

En otro script, intento abrir un archivo guardado previamente:

markers = np.fromfile("markers.txt")

Y eso es lo que obtengo ...

ingrese la descripción de la imagen aquí

Los datos guardados primero se ven así:

0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00

Pero cuando guardo los datos recién cargados mediante el uso del mismo método, es decir. numpy.savetxt()se parece a esto:

1.398043286095131769e-76
1.398043286095288860e-76
1.396426376485745879e-76
1.398043286055061908e-76
1.398043286095288860e-76
1.182950697433698368e-76
1.398043275797188953e-76
1.398043286095288860e-76
1.210894289234927752e-99
1.398040649781712473e-76

¿Qué estoy haciendo mal? PD: no hay otra operación "entre bastidores" que realice. Solo guardando y cargando, y eso es lo que obtengo. Gracias de antemano.

bluevoxel
fuente
¿Cuál es la salida del archivo de texto? ¿Por qué no escribir en un archivo CSV?
4
¿Necesita guardar y cargar como archivos de texto legibles por humanos? Será más rápido (y los archivos serán más compactos) si guarda / carga archivos binarios usando np.save()y np.load().
ali_m
Gracias por tu consejo. Eso ayudo. Sin embargo, ¿puedes explicar por qué es lo que es y si hay alguna forma de permitir guardar datos en formato * .txt y cargarlos sin quebraderos de cabeza? Por ejemplo, cuando uno quiere trabajar con matlab, java u otras herramientas / lenguajes.
bluevoxel
3
Para pasar matrices a / desde MATLAB, puede usar scipy.io.savematy scipy.io.loadmat.
ali_m
2
El valor predeterminado para fromfilees leer los datos como binarios. loadtxtes el emparejamiento correcto con savetxt. Mira la documentación de la función.
hpaulj

Respuestas:

146

La forma más confiable que he encontrado para hacer esto es usar np.savetxtcon np.loadtxty no np.fromfilecuál es más adecuado para archivos binarios escritos con tofile. Los métodos np.fromfiley np.tofileescriben y leen archivos binarios mientras que np.savetxtescriben un archivo de texto. Así por ejemplo:

In [1]: a = np.array([1, 2, 3, 4])
In [2]: np.savetxt('test1.txt', a, fmt='%d')
In [3]: b = np.loadtxt('test1.txt', dtype=int)
In [4]: a == b
Out[4]: array([ True,  True,  True,  True], dtype=bool)

O:

In [5]: a.tofile('test2.dat')
In [6]: c = np.fromfile('test2.dat', dtype=int)
In [7]: c == a
Out[7]: array([ True,  True,  True,  True], dtype=bool)

Utilizo el método anterior incluso si es más lento y crea archivos más grandes (a veces): el formato binario puede depender de la plataforma (por ejemplo, el formato de archivo depende del endianness de su sistema).

Existe un formato independiente de la plataforma para matrices NumPy, que se puede guardar y leer con np.savey np.load:

In  [8]: np.save('test3.npy', a)    # .npy extension is added if not given
In  [9]: d = np.load('test3.npy')
In [10]: a == d
Out[10]: array([ True,  True,  True,  True], dtype=bool)
xnx
fuente
47
.npyLos archivos (por ejemplo, generados por np.save()) son independientes de la plataforma y serán más compactos y rápidos de crear que los archivos de texto.
ali_m
2
también np.savezsi desea comprimir la salida.
tegan
3
@tegan np.savezguarda varias matrices sin comprimir; las np.savez_compressedcomprimirá; todavía no hay ninguna np.save_compressed. Ver docs.scipy.org/doc/numpy-1.15.1/reference/routines.io.html
Brian Burns
1
Gracias xnx Estaba teniendo el mismo problema (con dtype float) usando np.savetxt con np.loadtxt resuelto
Yogesh
Tuve un problema con los datos de guardado de pickle superiores a 2 GB. Gracias a xnx el problema se resolvió usando a.tofile y np.fromfile.
Azr
47
np.save('data.npy', num_arr) # save
new_num_arr = np.load('data.npy') # load
Sherzod
fuente
¿Hay algún problema con el uso pickle?
Charlie Parker
por ejemplo, para que podamos cargar los datos con lo que x = db["x"]sigue y = db["y"]?
Charlie Parker
3

np.fromfile()tiene un sep=argumento de palabra clave:

Separador entre elementos si el archivo es un archivo de texto. El separador vacío (“”) significa que el archivo debe tratarse como binario. Los espacios (””) en el separador coinciden con cero o más caracteres de espacio en blanco. Un separador que consta solo de espacios debe coincidir con al menos un espacio en blanco.

El valor predeterminado de sep=""significa que np.fromfile()intenta leerlo como un archivo binario en lugar de un archivo de texto separado por espacios, por lo que obtiene valores sin sentido. Si lo np.fromfile('markers.txt', sep=" ")usas obtendrás el resultado que buscas.

Sin embargo, como han señalado otros, np.loadtxt()es la forma preferida de convertir archivos de texto en matrices numpy y, a menos que el archivo deba ser legible por humanos, generalmente es mejor usar formatos binarios en su lugar (por ejemplo, np.load()/ np.save()).

ali_m
fuente
¿Hay algún problema con el uso pickle?
Charlie Parker
0

Para una respuesta corta, debe usar np.savey np.load. La ventaja de estos es que están hechos por desarrolladores de la biblioteca numpy y ya funcionan (además, es probable que ya estén optimizados muy bien), por ejemplo.

import numpy as np
from pathlib import Path

path = Path('~/data/tmp/').expanduser()
path.mkdir(parents=True, exist_ok=True)

lb,ub = -1,1
num_samples = 5
x = np.random.uniform(low=lb,high=ub,size=(1,num_samples))
y = x**2 + x + 2

np.save(path/'x', x)
np.save(path/'y', y)

x_loaded = np.load(path/'x.npy')
y_load = np.load(path/'y.npy')

print(x is x_loaded) # False
print(x == x_loaded) # [[ True  True  True  True  True]]

Respuesta ampliada:

Al final, realmente depende de sus necesidades porque también puede guardarlo en formato legible por humanos (consulte este Volcado de una matriz NumPy en un archivo csv ) o incluso con otras bibliotecas si sus archivos son extremadamente grandes (consulte esta mejor manera de preservar matrices numpy en disco para una discusión ampliada).

Sin embargo, (haciendo una expansión ya que usa la palabra "correctamente" en su pregunta) todavía creo que usar la función numpy lista para usar (¡y la mayoría del código!) Probablemente satisfaga la mayoría de las necesidades de los usuarios. La razón más importante es que ya funciona . Tratar de usar otra cosa por cualquier otra razón puede llevarlo a una madriguera inesperadamente LARGA para descubrir por qué no funciona y forzarlo a que funcione.

Tomemos, por ejemplo, intentar salvarlo con pepinillo. Lo intenté solo por diversión y me tomó al menos 30 minutos darme cuenta de que pickle no guardaría mis cosas a menos que abriera y leyera el archivo en modo bytes con wb. Tomó tiempo para google, probar cosas, entender el mensaje de error, etc. Un pequeño detalle, pero el hecho de que ya me obligara a abrir un archivo complicó las cosas de maneras inesperadas. Para agregar que me obligó a volver a leer esto (que por cierto es algo confuso) ¿ Diferencia entre los modos a, a +, w, w + y r + en la función abierta incorporada? .

Entonces, si hay una interfaz que satisface sus necesidades, úsela a menos que tenga una ( muy ) buena razón (por ejemplo, compatibilidad con matlab o por alguna razón, realmente desea leer el archivo e imprimir en python realmente no satisface sus necesidades, lo cual podría ser cuestionable). Además, lo más probable es que, si necesita optimizarlo, lo descubra más adelante (en lugar de pasar años depurando cosas inútiles como abrir un simple archivo numpy).

Así que usa la interfaz / numpy provide . Puede que no sea perfecto, lo más probable es que esté bien, especialmente para una biblioteca que ha existido durante tanto tiempo.

Ya gasté el almacenamiento y la carga de datos con numpy de muchas maneras, así que diviértete, ¡espero que te ayude!

import numpy as np
import pickle
from pathlib import Path

path = Path('~/data/tmp/').expanduser()
path.mkdir(parents=True, exist_ok=True)

lb,ub = -1,1
num_samples = 5
x = np.random.uniform(low=lb,high=ub,size=(1,num_samples))
y = x**2 + x + 2

# using save (to npy), savez (to npz)
np.save(path/'x', x)
np.save(path/'y', y)
np.savez(path/'db', x=x, y=y)
with open(path/'db.pkl', 'wb') as db_file:
    pickle.dump(obj={'x':x, 'y':y}, file=db_file)

## using loading npy, npz files
x_loaded = np.load(path/'x.npy')
y_load = np.load(path/'y.npy')
db = np.load(path/'db.npz')
with open(path/'db.pkl', 'rb') as db_file:
    db_pkl = pickle.load(db_file)

print(x is x_loaded)
print(x == x_loaded)
print(x == db['x'])
print(x == db_pkl['x'])
print('done')

Algunos comentarios sobre lo que aprendí:

  • np.savecomo se esperaba, esto ya lo comprime bien (consulte https://stackoverflow.com/a/55750128/1601580 ), funciona de inmediato sin abrir ningún archivo. Limpiar. Fácil. Eficiente. Úselo.
  • np.savezusa un formato sin comprimir (ver documentos ) Save several arrays into a single file in uncompressed .npz format.Si decide usar esto (se le advirtió que se alejara de la solución estándar, ¡así que espere errores!), puede descubrir que necesita usar nombres de argumentos para guardarlo, a menos que desee utilice los nombres predeterminados. Así que no use esto si el primero ya funciona (¡o cualquier trabajo lo usa!)
  • Pickle también permite la ejecución de código arbitrario. Es posible que algunas personas no quieran usar esto por razones de seguridad.
  • Los archivos legibles por humanos son costosos de hacer, etc. Probablemente no valga la pena.
  • hay algo llamado hdf5para archivos grandes. ¡Frio! https://stackoverflow.com/a/9619713/1601580

Tenga en cuenta que esta no es una respuesta exhaustiva. Pero para otros recursos, verifique esto:

Charlie Parker
fuente