2011-03-29 24 views
19

Dado un archivo CSV grande (10s de GB) de texto/números mezclados, ¿cuál es la forma más rápida de crear un archivo hdf5 con el mismo contenido, mientras se mantiene el uso de la memoria como razonable? Me gustaría usar el módulo h5py si es posible.¿La forma más rápida de escribir archivos hdf5 con Python?

En el siguiente ejemplo de juguete, he encontrado una forma increíblemente lenta e increíblemente rápida de escribir datos en hdf5. ¿Sería mejor práctica escribir en hdf5 en trozos de 10,000 filas más o menos? ¿O hay una mejor manera de escribir una gran cantidad de datos en un archivo como este?

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 
+0

Leer en una matriz numpy y evitar el bucle mediante el envío de toda la gama – Benjamin

+1

@Benjamin: ¿y si la matriz es demasiado grande como para mantener en la memoria? –

+0

Creo que necesitas darnos una idea de cómo quieres que tu archivo hdf5 esté estructurado –

Respuesta

5

Evitaría fragmentar los datos y almacenaría los datos como series de conjuntos de datos de matriz única (siguiendo la línea de lo que sugiere Benjamin). Acabo de cargar la salida de una aplicación empresarial en la que he estado trabajando en HDF5, y pude empaquetar unos 4.5 mil millones de tipos de datos compuestos como 450,000 conjuntos de datos, cada uno con una variedad de 10.000 datos. Las escrituras y lecturas ahora parecen bastante instantáneas, pero fueron dolorosamente lentas cuando inicialmente intenté fragmentar los datos.

¡Solo una idea!

Actualización:

Estos son un par de fragmentos levantadas de mi código real (estoy de codificación en C vs Python, pero usted debe tener una idea de lo que estoy haciendo) y modificados para mayor claridad. Estoy escribiendo números enteros largos sin signo en matrices (10,000 valores por matriz) y leyéndolos cuando necesito un valor real

Este es mi código de escritor típico. En este caso, simplemente estoy escribiendo una secuencia de enteros larga 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 hacerlo (es decir, podría usar hiperplanos para obtener el valor), pero esta fue la solución más limpia con respecto a mi bastante disciplinado proceso de desarrollo Agile/BDD.

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 llevar es el bucle interior en el código escrito y la división de enteros y operaciones mod para obtener el índice de la matriz de conjunto de datos y el índice del valor deseado en la matriz. Avíseme si esto es lo suficientemente claro para que pueda armar algo similar o mejor en h5py. En C, esto es absolutamente simple y me da tiempos de lectura/escritura significativamente mejores vs.una solución fragmentada de conjunto de datos. Además, dado que no puedo usar compresión con conjuntos de datos compuestos de todos modos, la aparente ventaja de la fragmentación es un punto discutible, por lo que todos mis compuestos se almacenan de la misma manera.

+0

Si es posible, ¿te importaría ampliar un poco más sobre cómo están estructurados tus datos? Si pudiera proporcionar un ejemplo concreto (código), estaría encantado de aceptar la respuesta. –

+0

He actualizado mi respuesta con el código. ¡Déjeme saber si esto ayuda! – Marc

3

no estoy seguro si esto es la manera más eficiente (y nunca he utilizado, yo sólo estoy tirando juntos algunas herramientas que he usado de forma independiente), pero se puede leer el archivo csv en un nuary recarray usando el matplotlib helper methods for csv.

Probablemente pueda encontrar la manera de leer los archivos csv en trozos también para evitar cargar todo en el disco. Luego, use la recarray (o las rebanadas en ella) para escribir el conjunto (o grandes fragmentos) en el conjunto de datos h5py. No estoy exactamente seguro de cómo h5py maneja recarrays, 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 agarrar las columnas que desee utilizando la palabra clave usecols, y después de sólo lectura en un conjunto especificado de líneas configurando adecuadamente las skip_header y skip_footer palabras clave.

3

utilizando la flexibilidad de numpy.loadtxt obtendrá los datos del archivo en un numpy array, que a su vez es perfecto 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) 
Cuestiones relacionadas