cargando arrays guardados usando numpy.save en modo agregado

Guardo los arreglos usando numpy.save () en modo agregado:

f = open("try.npy", 'ab') sp.save(f,[1, 2, 3, 4, 5]) sp.save(f,[6, 7, 8, 9, 10]) f.close() 

¿Puedo cargar los datos en modo LIFO? Es decir, si deseo cargar ahora la matriz 6-10, necesito cargar dos veces (use b):

 f = open("try.npy", 'r') a = sp.load(f) b = sp.load(f) f.close() 

o puedo cargar directamente el segundo guardado adjunto?

Estoy un poco sorprendido de que esta operación secuencial de guardar y guardar funcione. No creo que esté documentado (por favor corríjame). Pero evidentemente, cada save es una unidad autónoma, y ​​la load lee hasta el final de esa unidad, en oposición al final del archivo.

Piense en cada load como un readline . No puedes leer solo la última línea de un archivo; Tienes que leer todos los anteriores.

Bueno, hay una forma de leer el último: utilizar seek para mover el archivo leído a un punto específico. Pero para hacer eso tienes que saber exactamente dónde comienza el bloque deseado.

np.savez es la forma intencionada de guardar varias matrices en un archivo, o más bien en un archivo zip.


save guarda dos partes, un encabezado que contiene información como dtype , shape y dtype , y una copia del búfer de datos de la matriz. El atributo nbytes da el tamaño del búfer de datos. Al menos este es el caso de los dtypes numéricos y de cadena.

save doc tiene un ejemplo de uso de un archivo abierto: con seek(0) para rebobinar el archivo para que lo use la load .

np.lib.npyio.format tiene más información sobre el formato de guardado. Parece que es posible determinar la longitud del encabezado leyendo sus primeros bytes. Probablemente podría usar funciones en el módulo para realizar todas estas lecturas y cálculos.


Si leo todo el archivo del ejemplo, obtengo:

 In [696]: f.read() Out[696]: b"\x93NUMPY\x01\x00F\x00 {'descr': ' 

Agregué saltos de línea para resaltar las distintas partes de este archivo. Observe que cada save comienza con \x93NUMPY .

Con un archivo abierto f , puedo leer el encabezado (o la primera matriz) con:

 In [707]: np.lib.npyio.format.read_magic(f) Out[707]: (1, 0) In [708]: np.lib.npyio.format.read_array_header_1_0(f) Out[708]: ((5,), False, dtype('int32')) 

y puedo cargar los datos con:

 In [722]: np.fromfile(f, dtype=np.int32, count=5) Out[722]: array([1, 2, 3, 4, 5]) 

Deduje esto de np.lib.npyio.format.read_array código de función.

Ahora el archivo está posicionado en:

 In [724]: f.tell() Out[724]: 100 

que es la cabecera de la siguiente matriz:

 In [725]: np.lib.npyio.format.read_magic(f) Out[725]: (1, 0) In [726]: np.lib.npyio.format.read_array_header_1_0(f) Out[726]: ((5,), False, dtype('int32')) In [727]: np.fromfile(f, dtype=np.int32, count=5) Out[727]: array([ 6, 7, 8, 9, 10]) 

y estamos en EOF.

Y sabiendo que int32 tiene 4 bytes, podemos calcular que los datos ocupan 20 bytes. Así que podríamos saltear una matriz leyendo el encabezado, calculando el tamaño del bloque de datos y seek allá para llegar a la siguiente matriz. Para arreglos pequeños, ese trabajo no vale la pena; pero para los muy grandes, puede ser útil.