En el anterior capítulo vimos como crear una estructura básica para nuestro fichero h5
. Ahora vamos a ver como rellenar tablas de ese mismo fichero.
Rellenar tablas
Ahora es tiempo de rellenar la tabla con datos sin sentido (datos aleatorios) y fechas. numpy
y datetime
nos facilitarán la tarea por lo que vamos a importarlos antes).
import numpy as np import datetime as dt
Abrimos de nuevo el fichero h5 que creamos en el anterior capítulo, pero en lugar de abrirlo en modo “write” lo abriremos en modo “append”.
h5file = tb.open_file("tabla_test.h5", mode="a")
Recuperamos la tabla que queremos llenar (indicando la ruta en la estructura del fichero hdf5) y usando la función getNode
:
tab = h5file.get_node("/carpeta1/datos_carpeta1_tabla1")
Para rellenar la tabla creamos un puntero (o constructor de líneas propio a la tabla) row
.
mis_datos = tab.row
Creamos los datos que usaremos para rellenar la tabla:
f0 = dt.date(2000, 1, 1) fechas = np.array( [int((f0 + dt.timedelta(days=1) * i).strftime("%Y%m%d")) for i in range(10000)], dtype = np.int32 ) x = np.random.randn(10000) y = np.random.randn(10000) z = np.random.randn(10000)
Llenamos la tabla de manera recursiva con el constructor de líneas mis_datos
y el método append
:
for i in range(10000): mis_datos['fecha'] = fechas[i] mis_datos['x'] = x[i] mis_datos['y'] = y[i] mis_datos['z'] = z[i] mis_datos.append()
Se llama al método flush
sobre la tabla para volcar y registrar efectivamente los datos en la tabla.
tab.flush()
Si queremos, podemos añadir meta-información a la tabla:
tab.attrs.nombre_sensor="medidas de un escaterómetro"
tab.attrs.numero_columnas = 3
Además de la meta-información que hemos añadido, el objeto tabla contenía ya un cierto número de atributos que podemos ver escribiendo lo siguiente en IPython
tab.attrs
que nos mostrará lo siguiente:
/carpeta1/datos_carpeta1_tabla1._v_attrs (AttributeSet), 14 attributes: [CLASS := 'TABLE', FIELD_0_FILL := 0, FIELD_0_NAME := 'fecha', FIELD_1_FILL := 0.0, FIELD_1_NAME := 'x', FIELD_2_FILL := 0.0, FIELD_2_NAME := 'y', FIELD_3_FILL := 0.0, FIELD_3_NAME := 'z', NROWS := 0, TITLE := 'ejemplo de tabla', VERSION := '2.7', nombre_sensor := 'medidas de un escaterómetro', numero_columnas := 3]
Finalmente, cerramos la tabla creada como vimos en el primer capítulo.
h5file.close()
Si queréis usar una aplicación gráfica para ver el alrchivo que hemos creado podéis usar hdfview (sudo apt-get install hdfview
) o vitables. En este caso os muestro un ejemplo con hdfview ya que vitables posíblemente lo veamos en uno de los próximos capítulos.
Bueno, ya tenemos algunos datos guardados en nuestro fichero HDF5. El próximo día veremos como anexar datos a una tabla ya existente.
Saludos.
Realmente muy ameno para trabajar. Muchas gracias Kiko!!!
En el puntero de datos ¿es igual de eficiente, si en el for se pone “tab.row[‘x’] = x[i]”? ya que tab.row es un método (con cara de parámetro), o es mejor evaluarlo una ves (mis_datos = tab.row) y luego usar esa variable directamente (como has hecho).
Hola, schriher.
row es un método de la clase Table pero a la vez es una clase escrita en Cython. Si haces:
print(type(tab.row)) # o print(type(mis_datos))
deberías ver:
class ‘tables.tableextension.Row’
(método row de la clase Table: https://github.com/PyTables/PyTables/blob/develop/tables/table.py#L594)
(código Cython de la clase Row: https://github.com/PyTables/PyTables/blob/4b6c0f4000c9e3621668583d09b144c781051e89/tables/tableextension.pyx#L672)
En la forma que tú dices, estás llamando al método cada vez que quieres insertar una nueva fila y eso puede ser más ‘caro’ que instanciar una vez la clase Row (que es un iterador).
Puedes hacer tú mismo una prueba rápida (lo siguiente está hecho en IPyhon3 en mi equipo):
##### AVISO: El siguiente código puede crear varios millones de filas nuevas en tu fichero h5
[sourcecode language=”python”]
def kk():
for i in range(2000):
mis_datos[‘fecha’] = fechas[i]
mis_datos[‘x’] = x[i]
mis_datos[‘y’] = y[i]
mis_datos[‘z’] = z[i]
mis_datos.append()
tab.flush()
def kk1():
for i in range(2000):
tab.row[‘fecha’] = fechas[i]
tab.row[‘x’] = x[i]
tab.row[‘y’] = y[i]
tab.row[‘z’] = z[i]
tab.row.append()
tab.flush()
%timeit kk()
%timeit kk1()
[/sourcecode]
La primera forma, kk, que es como se indica en el tutorial y en la documentación oficial de PyTables, nos da lo siguiente:
1000 loops, best of 3: 1.85 ms per loop
Mientras que la forma que propones tú, kk1, nos da el siguiente resultado:
100 loops, best of 3: 4.17 ms per loop
por lo que sería entre 2 y 3 veces más lento.
Muchas gracias Kiko! mas o menos eso pensaba, pero no se me había ocurrido probarlo así, excelente!!!
Solo un detalle si el Aviso tenia la intensión de hacerme pensar antes de probar fue todo lo contrario, leí Aviso y abrí un terminal para probarlo jejeje el archivo terminó con mas de 160 MB.