update - ¿La forma más rápida de escribir archivos HDF5 con Python?
install hdf5 (3)
Dado un archivo CSV grande (10s de GB) de texto / números mixtos, ¿cuál es la forma más rápida de crear un archivo HDF5 con el mismo contenido, manteniendo el uso de memoria razonable?
Me gustaría usar el módulo h5py
si es posible.
En el siguiente ejemplo de juguete, he encontrado una manera increíblemente lenta e increíblemente rápida de escribir datos en HDF5. ¿Sería una buena práctica escribir en HDF5 en trozos de 10,000 filas o menos? ¿O hay una mejor manera de escribir una gran cantidad de datos en un archivo de este tipo?
import h5py
n = 10000000
f = h5py.File(''foo.h5'',''w'')
dset = f.create_dataset(''int'',(n,),''i'')
# this is terribly slow
for i in xrange(n):
dset[i] = i
# instantaneous
dset[...] = 42
Evitaría fragmentar los datos y almacenarlos como series de conjuntos de datos de matriz única (en la línea de lo que sugiere Benjamin). Acabo de terminar de cargar la salida de una aplicación empresarial en la que he estado trabajando en HDF5, y pude empaquetar aproximadamente 4.5 billones de tipos de datos compuestos en 450,000 conjuntos de datos, cada uno con una matriz de datos de 10,000. Las escrituras y lecturas ahora parecen bastante instantáneas, pero fueron extremadamente lentas cuando inicialmente intenté fragmentar los datos.
¡Solo un pensamiento!
Actualizar:
Estos son un par de fragmentos extraídos de mi código real (estoy codificando en C vs. Python, pero deberías tener una idea de lo que estoy haciendo) y modificarlos para mayor claridad. Solo escribo enteros largos sin signo en matrices (10.000 valores por matriz) y los vuelvo a leer cuando necesito un valor real
Este es mi código de escritor típico. En este caso, simplemente estoy escribiendo una larga secuencia entera sin signo en una secuencia de matrices y cargando cada secuencia de matriz en hdf5 a medida que se crean.
//Our dummy data: a rolling count of long unsigned integers
long unsigned int k = 0UL;
//We''ll use this to store our dummy data, 10,000 at a time
long unsigned int kValues[NUMPERDATASET];
//Create the SS adata files.
hid_t ssdb = H5Fcreate(SSHDF, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
//NUMPERDATASET = 10,000, so we get a 1 x 10,000 array
hsize_t dsDim[1] = {NUMPERDATASET};
//Create the data space.
hid_t dSpace = H5Screate_simple(1, dsDim, NULL);
//NUMDATASETS = MAXSSVALUE / NUMPERDATASET, where MAXSSVALUE = 4,500,000,000
for (unsigned long int i = 0UL; i < NUMDATASETS; i++){
for (unsigned long int j = 0UL; j < NUMPERDATASET; j++){
kValues[j] = k;
k += 1UL;
}
//Create the data set.
dssSet = H5Dcreate2(ssdb, g_strdup_printf("%lu", i), H5T_NATIVE_ULONG, dSpace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
//Write data to the data set.
H5Dwrite(dssSet, H5T_NATIVE_ULONG, H5S_ALL, H5S_ALL, H5P_DEFAULT, kValues);
//Close the data set.
H5Dclose(dssSet);
}
//Release the data space
H5Sclose(dSpace);
//Close the data files.
H5Fclose(ssdb);
Esta es una versión ligeramente modificada de mi código de lector. Hay formas más elegantes de hacer esto (es decir, podría usar los hiperplanos para obtener el valor), pero esta fue la solución más limpia con respecto a mi proceso de desarrollo Agile / BDD bastante disciplinado.
unsigned long int getValueByIndex(unsigned long int nnValue){
//NUMPERDATASET = 10,000
unsigned long int ssValue[NUMPERDATASET];
//MAXSSVALUE = 4,500,000,000; i takes the smaller value of MAXSSVALUE or nnValue
//to avoid index out of range error
unsigned long int i = MIN(MAXSSVALUE-1,nnValue);
//Open the data file in read-write mode.
hid_t db = H5Fopen(_indexFilePath, H5F_ACC_RDONLY, H5P_DEFAULT);
//Create the data set. In this case, each dataset consists of a array of 10,000
//unsigned long int and is named according to its integer division value of i divided
//by the number per data set.
hid_t dSet = H5Dopen(db, g_strdup_printf("%lu", i / NUMPERDATASET), H5P_DEFAULT);
//Read the data set array.
H5Dread(dSet, H5T_NATIVE_ULONG, H5S_ALL, H5S_ALL, H5P_DEFAULT, ssValue);
//Close the data set.
H5Dclose(dSet);
//Close the data file.
H5Fclose(db);
//Return the indexed value by using the modulus of i divided by the number per dataset
return ssValue[i % NUMPERDATASET];
}
La principal conclusión es el bucle interno en el código de escritura y las operaciones de división y modificación de enteros para obtener el índice de la matriz del conjunto de datos y el índice del valor deseado en esa matriz. Avísame si esto es lo suficientemente claro para que puedas armar algo similar o mejor en h5py. En C, esto es muy simple y me da tiempos de lectura / escritura significativamente mejores que una solución de conjunto de datos fragmentados. Además, ya que no puedo usar la compresión con conjuntos de datos compuestos de todos modos, el lado positivo aparente de la fragmentación es un punto discutible, por lo que todos mis compuestos se almacenan de la misma manera.
No estoy seguro de si esta es la forma más eficiente (y nunca la he usado; solo estoy juntando algunas herramientas que he usado de forma independiente), pero puedes leer el archivo csv en una nueva versión con el sistema matplotlib Métodos de ayuda para CSV .
Probablemente pueda encontrar una manera de leer los archivos csv en trozos y evitar cargar todo el contenido en el disco. Luego, use el recarray (o los cortes) para escribir el conjunto de datos (o partes grandes de él) en el conjunto de datos h5py. No estoy exactamente seguro de cómo h5py maneja las reparaciones, pero la documentación indica que debería estar bien.
Básicamente, si es posible, intente escribir grandes porciones de datos a la vez en lugar de iterar sobre elementos individuales.
Otra posibilidad para leer el archivo csv es simplemente numpy.genfromtxt
Puede tomar las columnas que desee con los usecols
palabras clave, y luego solo leer en un conjunto específico de líneas configurando correctamente las palabras clave skip_header
y skip_footer
.
al utilizar la flexibilidad de numpy.loadtxt
, los datos del archivo se convertirán en una numpy array
, que a su vez es perfecta para inicializar el conjunto de datos hdf5
.
import h5py
import numpy as np
d = np.loadtxt(''data.txt'')
h = h5py.File(''data.hdf5'', ''w'')
dset = h.create_dataset(''data'', data=d)