Cómo usar archivos HDF5 en Python

Hola a todos!

Se acerca el lanzamiento del curso "Desarrollador web en Python" , respectivamente, todavía compartimos artículos interesantes y nos invitan a nuestras lecciones abiertas, donde puedes ver material interesante, conocer maestros y hacerles preguntas.

Vamos!

HDF5 permite el almacenamiento eficiente de grandes cantidades de datos

Cuando se trabaja con grandes volúmenes de datos, ya sean experimentales o simulados, almacenarlos en varios archivos de texto no es muy eficiente. Algunas veces necesita acceder a un subconjunto específico de datos y desea hacerlo rápidamente. En estas situaciones, el formato HDF5 resuelve ambos problemas gracias a una biblioteca incorporada altamente optimizada. HDF5 se usa ampliamente en entornos científicos y tiene una excelente implementación en Python diseñada para trabajar con NumPy desde el primer momento.

El formato HDF5 admite archivos de cualquier tamaño, y cada archivo tiene una estructura interna que le permite buscar un conjunto de datos específico. Esto puede considerarse como un archivo separado con su propia estructura jerárquica, así como un conjunto de carpetas y subcarpetas. De manera predeterminada, los datos se almacenan en formato binario y la biblioteca es compatible con diferentes tipos de datos. Una de las opciones más importantes para el formato HDF5 es que le permite adjuntar metadatos a cada elemento de la estructura, por lo que es ideal para crear archivos sin conexión.


En Python, se puede construir una interfaz con el formato HDF5 utilizando el paquete h5py. Una de las características más interesantes de este paquete es que los datos se leen de un archivo solo cuando es necesario. Imagine que tiene una matriz muy grande que no cabe en su RAM disponible. Por ejemplo, podría generar una matriz en una computadora con diferentes especificaciones, a diferencia de la que usa para el análisis de datos. El formato HDF5 le permite elegir qué elementos de la matriz leer con una sintaxis equivalente a NumPy. Entonces puede trabajar con datos almacenados en el disco duro, y no en la RAM, sin cambios significativos en el código existente.

En este artículo, veremos cómo puede usar h5py para almacenar y recuperar datos de su disco duro. Discutiremos diferentes formas de almacenar datos y cómo optimizar el proceso de lectura. Todos los ejemplos que aparecen en este artículo también están disponibles en nuestro repositorio de Github .

Instalación

El formato HDF5 es compatible con el Grupo HDF y se basa en estándares de código abierto, lo que significa que sus datos siempre estarán disponibles, incluso si el grupo desaparece. El soporte de Python se proporciona a través del paquete h5py , que se puede instalar a través de pip. Recuerde que debe usar el entorno virtual para las pruebas:

pip install h5py 

Este comando también instalará NumPy si no está en su entorno.

Si está buscando una herramienta gráfica para examinar el contenido de sus archivos HDF5, puede instalar el Visor HDF5 . Está escrito en Java, por lo que debería funcionar en casi cualquier computadora.

Almacenamiento básico de datos y lectura

Pasemos a usar la biblioteca HDF5. Crearemos un nuevo archivo y guardaremos una matriz aleatoria de NumPy en él.

 import h5py import numpy as np arr = np.random.randn(1000) with h5py.File('random.hdf5', 'w') as f: dset = f.create_dataset("default", data=arr) 

Las primeras líneas son bastante simples: importamos los paquetes h5py y NumPy y creamos una matriz con valores aleatorios. Abrimos el archivo random.hdf5 con permiso de escritura w, lo que significa que si ya existe un archivo con el mismo nombre, se sobrescribirá. Si desea guardar el archivo y aún así poder escribir en él, puede abrirlo con el atributo a en lugar de w. Creamos un conjunto de datos llamado predeterminado y establecemos los datos como una matriz aleatoria creada anteriormente. Los conjuntos de datos son los custodios de nuestros datos, principalmente componentes básicos del formato HDF5.

Una nota

Si no está familiarizado con la declaración with, debo tener en cuenta que esta es una forma conveniente de abrir y cerrar archivos. Incluso si ocurre un error dentro with , el archivo se cerrará. Si por alguna razón no está utilizando, nunca olvide agregar el f.close() al final. La declaración with funciona con cualquier archivo, no solo con archivos HDF.

Podemos leer los datos casi de la misma manera que leemos el archivo NumPy:

 with h5py.File('random.hdf5', 'r') as f: data = f['default'] print(min(data)) print(max(data)) print(data[:15]) 

Abrimos el archivo con el atributo de lectura r y restauramos los datos accediendo directamente al conjunto de datos llamado predeterminado. Si abre el archivo y no sabe qué conjuntos de datos están disponibles, puede obtenerlos:

 for key in f.keys(): print(key) 

Después de leer el conjunto de datos que desea, puede usarlo como si estuviera usando cualquier matriz NumPy. Por ejemplo, puede encontrar los valores máximos y mínimos o seleccionar los primeros 15 valores de la matriz. Sin embargo, estos ejemplos simples ocultan muchas cosas que suceden debajo del capó, y deben discutirse para comprender todo el potencial de HDF5.

En el ejemplo anterior, puede usar los datos como una matriz. Por ejemplo, puede referirse al tercer elemento ingresando datos [2], o puede obtener un rango de valores de datos [1: 3]. Tenga en cuenta: los datos no son una matriz, es un conjunto de datos. Puede verlo escribiendo print(type(data)) . Los conjuntos de datos funcionan de una manera completamente diferente a las matrices, porque su información se almacena en el disco duro y no la cargan en la RAM si no los usamos. El siguiente código, por ejemplo, no funcionará:

 f = h5py.File('random.hdf5', 'r') data = f['default'] f.close() print(data[1]) 

El error que aparece es un poco engorroso, pero la última línea es muy útil:

 ValueError: Not a dataset (not a dataset) 

El error significa que estamos intentando acceder a un conjunto de datos al que ya no tenemos acceso. Esto es un poco confuso, pero sucede porque cerramos el archivo y, por lo tanto, ya no se nos permite acceder al segundo valor en los datos. Cuando asignamos f ['predeterminado'] a datos variables, en realidad no leemos los datos del archivo, en su lugar, generamos un puntero a donde están los datos en el disco duro. Por otro lado, este código funcionará:

 f = h5py.File('random.hdf5', 'r') data = f['default'][:] f.close() print(data[10]) 

Tenga en cuenta que la única diferencia es que agregamos [:] después de leer el conjunto de datos. Muchos otros manuales se detienen en tales ejemplos, sin siquiera demostrar todo el potencial del formato HDF5 con el paquete h5py. Debido a los ejemplos que hemos examinado hasta ahora, puede que se pregunte: ¿por qué usar HDF5 si guardar archivos NumPy le brinda la misma funcionalidad? Veamos las características del formato HDF5.

Lectura selectiva de archivos HDF5

Hasta ahora, hemos visto que cuando leemos un conjunto de datos, todavía no estamos leyendo datos del disco, sino que creamos un enlace a un lugar específico en el disco duro. Podemos ver qué sucede si, por ejemplo, leemos explícitamente los primeros 10 elementos de un conjunto de datos:

 with h5py.File('random.hdf5', 'r') as f: data_set = f['default'] data = data_set[:10] print(data[1]) print(data_set[1]) 

Dividimos el código en diferentes líneas para hacerlo más explícito, pero puede ser más sintético en sus proyectos. En las líneas anteriores, primero leemos el archivo y luego leemos el conjunto de datos predeterminado. Asignamos los primeros 10 elementos del conjunto de datos a la variable de datos. Después de cerrar el archivo (cuando finaliza), podemos acceder a los valores almacenados en los datos, pero data_set arrojará un error. Tenga en cuenta que solo leemos desde el disco cuando accedemos explícitamente a los primeros 10 elementos de un conjunto de datos. Si observa los tipos de datos y data_set, verá que son realmente diferentes. El primero es una matriz NumPy, y el segundo es un conjunto de datos h5py.

El mismo comportamiento es relevante en escenarios más complejos. Creemos un nuevo archivo, esta vez con dos conjuntos de datos, y seleccionemos los elementos de uno de ellos en función de los elementos del otro. Comencemos creando un nuevo archivo y almacenando datos; esta parte es la más simple:

 import h5py import numpy as np arr1 = np.random.randn(10000) arr2 = np.random.randn(10000) with h5py.File('complex_read.hdf5', 'w') as f: f.create_dataset('array_1', data=arr1) f.create_dataset('array_2', data=arr2) 

Tenemos dos conjuntos de datos llamados array_1 y array_2, cada uno de los cuales contiene una matriz aleatoria NumPy. Queremos leer los valores de array_2 que corresponden a elementos donde los valores de array_1 son positivos. Podemos intentar hacer algo como esto:

 with h5py.File('complex_read.hdf5', 'r') as f: d1 = f['array_1'] d2 = f['array_2'] data = d2[d1>0] 

Pero eso no funcionará. d1 es un conjunto de datos y no se puede comparar con un número entero. La única forma es leer los datos del disco y luego compararlos. Por lo tanto, obtenemos algo como esto:

 with h5py.File('complex_read.hdf5', 'r') as f: d1 = f['array_1'] d2 = f['array_2'] data = d2[d1[:]>0] 

El primer conjunto de datos d1 se carga completamente en la memoria cuando hacemos d1 [:], pero del segundo conjunto de datos d2 tomamos solo algunos elementos. Si el conjunto de datos d1 era demasiado grande para cargarlo en la memoria por completo, podríamos trabajar dentro de un bucle.

 with h5py.File('complex_read.hdf5', 'r') as f: d1 = f['array_1'] d2 = f['array_2'] data = [] for i in range(len(d1)): if d1[i] > 0: data.append(d2[i]) print('The length of data with a for loop: {}'.format(len(data))) 

Por supuesto, hay problemas con la eficacia de la lectura por elementos y la adición de elementos a la lista, pero este es un muy buen ejemplo de una de las mayores ventajas de usar HDF5 sobre archivos de texto o NumPy. Dentro del bucle, cargamos solo un elemento en la memoria. En nuestro ejemplo, cada elemento es simplemente un número, pero podría ser cualquier cosa: desde texto a imagen o video.

Como siempre, dependiendo de su aplicación, debe decidir si desea leer toda la matriz en la memoria o no. A veces ejecuta simulaciones en una computadora específica con una gran cantidad de memoria, pero no tiene las mismas características en su computadora portátil y se ve obligado a leer fragmentos de sus datos. Recuerde que la lectura desde el disco duro es relativamente lenta, especialmente si usa el HDD en lugar de los discos SDD o incluso más si lee desde un disco de red.

Escribir selectivamente en archivos HDF5

En los ejemplos anteriores, agregamos datos al conjunto de datos tan pronto como se creó. Sin embargo, para muchas aplicaciones necesita guardar datos durante la generación. HDF5 le permite guardar datos de la misma manera que los lee. Veamos cómo crear un conjunto de datos vacío y agregarle algunos datos.

 arr = np.random.randn(100) with h5py.File('random.hdf5', 'w') as f: dset = f.create_dataset("default", (1000,)) dset[10:20] = arr[50:60] 

Las dos primeras líneas son las mismas que antes, excepto para create_dataset . No agregamos datos cuando los creamos, solo creamos un conjunto de datos vacío que puede contener hasta 1000 elementos. Con la misma lógica que antes, cuando leemos ciertos elementos de un conjunto de datos, en realidad escribimos en el disco solo cuando asignamos valores a ciertos elementos de la variable dset. En el ejemplo anterior, solo asignamos valores a un subconjunto de la matriz, con índices del 10 al 19.

Advertencia

No es del todo cierto lo que escribe en el disco cuando asigna valores a un conjunto de datos. El momento exacto depende de varios factores, incluido el estado del sistema operativo. Si el programa se cierra demasiado pronto, puede suceder que no todo se grabe. Es muy importante usar siempre el método close() , y en caso de que escriba en etapas, también puede usar flush() para forzar la entrada. Usar con evita muchos problemas de escritura.

Si lee el archivo e imprime los primeros 20 valores del conjunto de datos, verá que todos son ceros, excepto los índices del 10 al 19. Hay un error común que puede provocar un dolor de cabeza notable. El siguiente código no guardará nada en el disco:

 arr = np.random.randn(1000) with h5py.File('random.hdf5', 'w') as f: dset = f.create_dataset("default", (1000,)) dset = arr 

Este error siempre causa muchos problemas, porque no comprenderá que no escribió nada hasta que intente leer el resultado. El problema aquí es que no especifica dónde desea almacenar los datos, simplemente sobrescribe la variable dset con una matriz NumPy. Dado que el conjunto de datos y la matriz tienen la misma longitud, debe usar dset [:] = arr. Este error ocurre con más frecuencia de lo que piensa, y dado que técnicamente no es incorrecto, no verá ningún error en el terminal y sus datos serán ceros.

Hasta ahora, siempre hemos trabajado con matrices unidimensionales, pero no estamos limitados a ellas. Por ejemplo, supongamos que queremos usar una matriz 2D, simplemente podemos hacer:

 dset = f.create_dataset('default', (500, 1024)) 

lo que nos permite almacenar datos en una matriz de 500x1024. Para usar un conjunto de datos, podemos usar la misma sintaxis que antes, pero teniendo en cuenta la segunda dimensión:

 dset[1,2] = 1 dset[200:500, 500:1024] = 123 

Especificar tipos de datos para optimizar el espacio.

Hasta ahora, hemos examinado solo la punta del iceberg de lo que HDF5 tiene para ofrecer. Además de la longitud de los datos que desea conservar, puede especificar el tipo de datos para optimizar el espacio. La documentación de h5py contiene una lista de todos los tipos compatibles, aquí solo mostramos algunos. Al mismo tiempo, trabajaremos con varios conjuntos de datos en un archivo.

 with h5py.File('several_datasets.hdf5', 'w') as f: dset_int_1 = f.create_dataset('integers', (10, ), dtype='i1') dset_int_8 = f.create_dataset('integers8', (10, ), dtype='i8') dset_complex = f.create_dataset('complex', (10, ), dtype='c16') dset_int_1[0] = 1200 dset_int_8[0] = 1200.1 dset_complex[0] = 3 + 4j 

En el ejemplo anterior, creamos tres conjuntos de datos diferentes, cada uno de los cuales tiene un tipo diferente. Enteros de 1 byte, enteros de 8 bytes y números complejos de 16 bytes. Solo almacenamos un número, incluso si nuestros conjuntos de datos pueden contener hasta 10 elementos. Puede leer los valores y ver qué se guardó realmente. Debe notarse aquí que un entero de 1 byte debe redondearse a 127 (en lugar de 1200), y un entero de 8 bytes debe redondearse a 1200 (en lugar de 1200.1).

Si alguna vez ha programado en lenguajes como C o Fortran, probablemente sepa qué significan los diferentes tipos de datos. Sin embargo, si siempre ha trabajado con Python, es posible que no haya encontrado ningún problema sin declarar explícitamente el tipo de datos con los que está trabajando. Es importante recordar que el número de bytes le indica cuántos números diferentes puede guardar. Si usa 1 byte, tiene 8 bits y, por lo tanto, puede almacenar 2 ^ 8 números diferentes. En el ejemplo anterior, los enteros son positivos, negativos y 0. Cuando usa enteros de 1 byte, puede almacenar valores de -128 a 127, en total son 2 ^ 8 números posibles. Esto es equivalente a usar 8 bytes, pero con una amplia gama de números.

El tipo de datos seleccionados afectará su tamaño. Primero, veamos cómo funciona esto con un ejemplo simple. Creemos tres archivos, cada uno con un conjunto de datos para 100,000 elementos, pero con diferentes tipos de datos. Guardaremos los mismos datos en ellos y luego compararemos sus tamaños. Creamos una matriz aleatoria para asignar a cada conjunto de datos para llenar la memoria. Recuerde que los datos se convertirán al formato especificado en el conjunto de datos.

 arr = np.random.randn(100000) f = h5py.File('integer_1.hdf5', 'w') d = f.create_dataset('dataset', (100000,), dtype='i1') d[:] = arr f.close() f = h5py.File('integer_8.hdf5', 'w') d = f.create_dataset('dataset', (100000,), dtype='i8') d[:] = arr f.close() f = h5py.File('float.hdf5', 'w') d = f.create_dataset('dataset', (100000,), dtype='f16') d[:] = arr f.close() 

Cuando verifique el tamaño de cada archivo, obtendrá algo como:

ArchivoTamaño (b)
entero_1102144
entero_9802144
flotar1602144

La relación entre tamaño y tipo de datos es clara. Cuando pasa de enteros de 1 byte a 8 bytes, el tamaño del archivo aumenta 8 veces, de manera similar, cuando va a 16 bytes, ocupa aproximadamente 16 veces más espacio. Pero el espacio no es el único factor importante a tener en cuenta; también debe tener en cuenta el tiempo que lleva escribir datos en el disco. Cuanto más tenga que escribir, más tardará. Dependiendo de su aplicación, puede ser crucial optimizar la lectura y escritura de datos.

Tenga en cuenta: si utiliza el tipo de datos incorrecto, también puede perder información. Por ejemplo, si tiene enteros de 8 bytes y los almacena como enteros de 1 byte, sus valores se truncarán. Cuando se trabaja en el laboratorio, los dispositivos que crean diferentes tipos de datos a menudo están disponibles. Algunas tarjetas DAQ tienen 16 bits, algunas cámaras funcionan con 8 bits, pero algunas pueden funcionar con 24. Es importante prestar atención a los tipos de datos, pero esto también es algo que los desarrolladores de Python pueden no tener en cuenta, porque no es necesario que explícitamente declarar tipo.

También es interesante recordar que la matriz predeterminada de NumPy será flotante con 8 bytes (64 bits) por elemento. Esto puede ser un problema si, por ejemplo, inicializa una matriz con ceros para almacenar datos, que deberían tener solo 2 bytes. El tipo de matriz en sí no cambiará, y si guarda los datos al crear el conjunto de datos (agregando data = my_array), el formato predeterminado será "f8", que es una matriz, pero no datos reales,

Pensar en los tipos de datos no es algo que sucede regularmente si trabajas con Python en aplicaciones simples. Sin embargo, debe tener en cuenta que existen tipos de datos y qué impacto pueden tener en sus resultados. Es posible que tenga discos duros grandes y que realmente no le importe el almacenamiento de archivos, pero cuando le importa la velocidad con la que ahorra, no hay otra forma que optimizar todos los aspectos de su código, incluidos los tipos de datos.

Compresión de datos

Al guardar datos, puede elegir la compresión utilizando diferentes algoritmos. El paquete h5py admite varios filtros de compresión, como GZIP, LZF y SZIP. Cuando se usa uno de los filtros de compresión, los datos se procesarán en su camino hacia el disco y, al leerlos, se desempaquetarán. Por lo tanto, no hay cambios especiales en el código. Podemos repetir el mismo experimento, guardando diferentes tipos de datos, pero usando un filtro de compresión. Nuestro código se ve así:

 import h5py import numpy as np arr = np.random.randn(100000) with h5py.File('integer_1_compr.hdf5', 'w') as f: d = f.create_dataset('dataset', (100000,), dtype='i1', compression="gzip", compression_opts=9) d[:] = arr with h5py.File('integer_8_compr.hdf5', 'w') as f: d = f.create_dataset('dataset', (100000,), dtype='i8', compression="gzip", compression_opts=9) d[:] = arr with h5py.File('float_compr.hdf5', 'w') as f: d = f.create_dataset('dataset', (100000,), dtype='f16', compression="gzip", compression_opts=9) d[:] = arr 

Elegimos gzip porque es compatible con todas las plataformas. Las opciones de compresión_opts especifican el nivel de compresión. Cuanto mayor sea el nivel, menos espacio ocuparán los datos, pero más tiempo debería funcionar el procesador. El nivel de compresión predeterminado es 4. Podemos ver las diferencias en nuestros archivos según el nivel de compresión:

TipoSin compresiónCompresión 9Compresión 4
entero_11021442801630463
entero_88021444332957971
flotar160214414695801469868

El efecto de la compresión en conjuntos de datos completos es mucho más notable que en los conjuntos de datos de punto flotante. Te dejo que descubras por qué la compresión funcionó tan bien en los primeros dos casos, pero no en el último. Como sugerencia: debe verificar qué datos está almacenando realmente.

La lectura de datos comprimidos no cambia ninguno de los códigos descritos anteriormente. La biblioteca principal HDF5 se encargará de extraer datos de conjuntos de datos comprimidos utilizando el algoritmo apropiado. Por lo tanto, si implementa compresión para guardar, no necesita cambiar el código que usa para leer.

La compresión de datos es una herramienta adicional que debe considerar junto con todos los demás aspectos del procesamiento de datos. Debe considerar el tiempo adicional del procesador y la relación de compresión efectiva para evaluar los beneficios de la compresión de datos dentro de su propia aplicación. El hecho de que sea transparente para el código posterior hace que sea increíblemente fácil probar y encontrar la mejor solución.

Redimensionar conjuntos de datos

Cuando está trabajando en un experimento, a veces es imposible saber qué tan grandes serán sus datos. Imagine que está grabando una película, tal vez la detendrá después de un segundo, tal vez después de una hora. Afortunadamente, HDF5 le permite cambiar el tamaño de los conjuntos de datos sobre la marcha con un bajo costo computacional. La longitud del conjunto de datos se puede exceder hasta el tamaño máximo. Este tamaño máximo se especifica al crear el conjunto de datos con la palabra clave maxshape:

 import h5py import numpy as np with h5py.File('resize_dataset.hdf5', 'w') as f: d = f.create_dataset('dataset', (100, ), maxshape=(500, )) d[:100] = np.random.randn(100) d.resize((200,)) d[100:200] = np.random.randn(100) with h5py.File('resize_dataset.hdf5', 'r') as f: dset = f['dataset'] print(dset[99]) print(dset[199]) 

Primero, crea un conjunto de datos para almacenar 100 valores y establece el tamaño máximo en 500 valores. Después de guardar el primer lote de valores, puede expandir el conjunto de datos para guardar los siguientes 100. Puede repetir el procedimiento hasta obtener un conjunto de datos con 500 valores. , N- . , , .

, , . , - ( , , ):

 with h5py.File('resize_dataset.hdf5', 'a') as f: dset = f['dataset'] dset.resize((300,)) dset[:200] = 0 dset[200:300] = np.random.randn(100) with h5py.File('resize_dataset.hdf5', 'r') as f: dset = f['dataset'] print(dset[99]) print(dset[199]) print(dset[299]) 

, , 200 200 299. , , .

, , , . 2D-, , — , 2D-. 3- HDF-, . , :

 with h5py.File('movie_dataset.hdf5', 'w') as f: d = f.create_dataset('dataset', (1024, 1024, 1), maxshape=(1024, 1024, None )) d[:,:,0] = first_frame d.resize((1024,1024,2)) d[:,:,1] = second_frame 

1024x1024 , . , , . maxshape None.

(Chunks)

, . (chunk) , .. . , , . , :

 dset = f.create_dataset("chunked", (1000, 1000), chunks=(100, 100)) 

, dset [0: 100,0: 100] . dset [200: 300, 200: 300], dset [100: 200, 400: 500] . . h5py, :

(Chunking) . 10 KiB 1 MiB, . , , .

(auto-chunking), . , maxshape. :

 dset = f.create_dataset("autochunk", (1000, 1000), chunks=True) 

(Groups)

. HDF5, , . (groups), , . , :

 import numpy as np import h5py arr = np.random.randn(1000) with h5py.File('groups.hdf5', 'w') as f: g = f.create_group('Base_Group') gg = g.create_group('Sub_Group') d = g.create_dataset('default', data=arr) dd = gg.create_dataset('default', data=arr) 

Base_Group , Sub_Group. default . , , :

 with h5py.File('groups.hdf5', 'r') as f: d = f['Base_Group/default'] dd = f['Base_Group/Sub_Group/default'] print(d[1]) print(dd[1]) 

, : Base_Group/default Base_Group/Sub_Group/default. , , , , . — keys():

 with h5py.File('groups.hdf5', 'r') as f: for k in f.keys(): print(k) 

, , for-. , . visit(), :

 def get_all(name): print(name) with h5py.File('groups.hdf5', 'r') as f: f.visit(get_all) 

, get_all , , name. visit, get_all. visit , , None, . , , Sub_Group, get_all :

 def get_all(name): if 'Sub_Group' in name: return name with h5py.File('groups.hdf5', 'r') as f: g = f.visit(get_all) print(g) 

visit , , None, , get_all. Sub_Group, get_all , Sub_Group . , g , , :

 with h5py.File('groups.hdf5', 'r') as f: g_name = f.visit(get_all) group = f[g_name] 

. — , visititems, : name object. :

 def get_objects(name, obj): if 'Sub_Group' in name: return obj with h5py.File('groups.hdf5', 'r') as f: group = f.visititems(get_objects) data = group['default'] print('First data element: {}'.format(data[0])) 

visititems , , , . , , . . , , .

HDF5

, HDF5, , . , , , , , , .. . , , 200x300x250. , , , , — , .

HDF5 -. .

 import time import numpy as np import h5py import os arr = np.random.randn(1000) with h5py.File('groups.hdf5', 'w') as f: g = f.create_group('Base_Group') d = g.create_dataset('default', data=arr) g.attrs['Date'] = time.time() g.attrs['User'] = 'Me' d.attrs['OS'] = os.name for k in g.attrs.keys(): print('{} => {}'.format(k, g.attrs[k])) for j in d.attrs.keys(): print('{} => {}'.format(j, d.attrs[j])) 

, attrs . , , . , . , , , update:

 with h5py.File('groups.hdf5', 'w') as f: g = f.create_group('Base_Group') d = g.create_dataset('default', data=arr) metadata = {'Date': time.time(), 'User': 'Me', 'OS': os.name,} f.attrs.update(metadata) for m in f.attrs.keys(): print('{} => {}'.format(m, f.attrs[m])) 

, , hdf5, . , . hdf5, . Python -. JSON, , , , pickle.

 import json with h5py.File('groups_dict.hdf5', 'w') as f: g = f.create_group('Base_Group') d = g.create_dataset('default', data=arr) metadata = {'Date': time.time(), 'User': 'Me', 'OS': os.name,} m = g.create_dataset('metadata', data=json.dumps(metadata)) 

, . , . , json.dumps, . , HDF5. , json.loads:

Pitón
 with h5py.File('groups_dict.hdf5', 'r') as f: metadata = json.loads(f['Base_Group/metadata'][()]) for k in metadata: print('{} => {}'.format(k, metadata[k])) 

json , . YAML, XML .. , , , attr , , .

HDF5

, . , , , . HDF , , , , , . , HDF .

HDF5 . , , . , . . SQL, HDFql , SQL HDF5.

. , , - , , . , . , , .

HDF5 — , . , , , , . HDF5 — , , .

El fin

, .

Source: https://habr.com/ru/post/es416309/


All Articles