Consulta HDF5 en Pandas

Tengo los siguientes datos (18,619,211 filas) almacenados como un objeto de dataframe pandas en el archivo hdf5:

date id2 w id 100010 1980-03-31 10401 0.000839 100010 1980-03-31 10604 0.020140 100010 1980-03-31 12490 0.026149 100010 1980-03-31 13047 0.033560 100010 1980-03-31 13303 0.001657 

donde id es índice y otros son columnas. date es np.datetime64 . Necesito realizar una consulta como esta (el código no funciona, por supuesto):

 db=pd.HDFStore('database.h5') data=db.select('df', where='id==id_i & date>bgdt & date<endt') 

Tenga en cuenta que id_i, bgdt, endt son todas variables, no valores reales y deben pasarse dentro de un bucle. por ejemplo:

dates son un índice de Pandas Period o un sello de fecha y hora, de cualquier manera, puedo convertir el uno al otro.

 dates=['1990-01', 1990-04','1990-09',......] 

id_list es una lista de identificadores

 id_list=[100010, 100011,1000012,.......] 

El bucle se ve así (la razón por la que hago el bucle es porque los datos son enormes, hay otros conjuntos de datos que tengo que consultar al mismo tiempo y luego realizo algunas operaciones)

 db=pd.HDFStore('database.h5') for id_i in id_list: for date in dates: bgdt=date-1 (move to previous month) endt=date-60 (previous 60 month) data=db.select('df', where='index==id_i & date>bgdt & date<endt') ...... 

Este problema tiene 2 partes:

  • No sé cómo consultar el índice y las columnas al mismo tiempo. El documento en pandas mostró cómo realizar consultas basadas en condiciones de índice O condiciones de columnas, pero no hay ejemplos sobre cómo realizar consultas basadas en ellas en el MISMO TIEMPO.
    • (Por cierto, esto es muy común en la documentación de Pandas. El documento generalmente muestra cosas muy simples como cómo hacer ‘A’, O cómo hacer ‘B’, pero no cómo hacer AMBOS ‘A’ y ‘B’. Una buena el ejemplo es la query uso en un dataframe de pandas de índice múltiple. El documento se basa en el level=0 O el level=1 , pero no hay ningún ejemplo sobre cómo hacer AMBOS EN EL MISMO TIEMPO.)
  • No sé cómo pasar tres variables id_i, bgdt, endt a la consulta. Sé cómo transmitir solo utilizando %s , pero no todos.
    • También estoy un poco confundido con el tipo de datos datetime. Parece que hay bastantes numpy.datetime64 pandas.Period : datetime.datetime , numpy.datetime64 , pandas.Period . Estoy trabajando principalmente en datos mensuales, así que pandas.Period es el más útil. Pero no puedo convertir fácilmente una columna (no índice) de marcas de tiempo (el tipo de fecha predeterminado de Pandas cuando se analiza a partir de datos sin procesar). ¿Hay algún tipo de datos que sea simplemente una ‘fecha’, no marcas de tiempo, no puntos, sino solo una FECHA simple con solo año, mes y día?

Muchos problemas, pero realmente AMO python y pandas (estoy tratando de mover mi flujo de trabajo de SAS a Python). Cualquier ayuda será apreciada!

Aquí están los documentos para consultar en columnas sin índice.

Crear los datos de prueba. No está claro cómo se construye el marco original, por ejemplo, si sus datos únicos y los rangos, por lo que he creado una muestra, con 10M filas, y un rango de fecha de varios niveles con la columna id.

 In [60]: np.random.seed(1234) In [62]: pd.set_option('display.max_rows',20) In [63]: index = pd.MultiIndex.from_product([np.arange(10000,11000),pd.date_range('19800101',periods=10000)],names=['id','date']) In [67]: df = DataFrame(dict(id2=np.random.randint(0,1000,size=len(index)),w=np.random.randn(len(index))),index=index).reset_index().set_index(['id','date']) In [68]: df Out[68]: id2 w id date 10000 1980-01-01 712 0.371372 1980-01-02 718 -1.255708 1980-01-03 581 -1.182727 1980-01-04 202 -0.947432 1980-01-05 493 -0.125346 1980-01-06 752 0.380210 1980-01-07 435 -0.444139 1980-01-08 128 -1.885230 1980-01-09 425 1.603619 1980-01-10 449 0.103737 ... ... ... 10999 2007-05-09 8 0.624532 2007-05-10 669 0.268340 2007-05-11 918 0.134816 2007-05-12 979 -0.769406 2007-05-13 969 -0.242123 2007-05-14 950 -0.347884 2007-05-15 49 -1.284825 2007-05-16 922 -1.313928 2007-05-17 347 -0.521352 2007-05-18 353 0.189717 [10000000 rows x 2 columns] 

Escriba los datos en el disco y muestre cómo crear una columna de datos (tenga en cuenta que los índices se pueden consultar automáticamente, esto permite que también se pueda consultar la ID2). Esto es de facto equivalente a hacer. Esto se encarga de abrir y cerrar la tienda (puede lograr lo mismo abriendo una tienda, agregando y cerrando).

Para consultar una columna, DEBE SER UNA COLUMNA DE DATOS o un índice del marco.

 In [70]: df.to_hdf('test.h5','df',mode='w',data_columns=['id2'],format='table') In [71]: !ls -ltr test.h5 -rw-rw-r-- 1 jreback users 430540284 May 26 17:16 test.h5 

Consultas

 In [80]: ids=[10101,10898] In [81]: start_date='20010101' In [82]: end_date='20010301' 

Puede especificar fechas como cadena (ya sea en línea o como variables; también puede especificar marcas de tiempo como objetos)

 In [83]: pd.read_hdf('test.h5','df',where='date>start_date & date 

Puedes usar listas en línea

 In [84]: pd.read_hdf('test.h5','df',where='date>start_date & date 

También puedes especificar expresiones booleanas.

 In [85]: pd.read_hdf('test.h5','df',where='date>start_date & date500 & id2<600') Out[85]: id2 w id date 10101 2001-01-12 534 -0.220692 2001-01-14 596 -2.225393 2001-01-16 596 0.956239 2001-01-30 513 -2.528996 2001-02-01 572 -1.877398 2001-02-13 569 -0.940748 2001-02-14 541 1.035619 2001-02-21 571 -0.116547 10898 2001-01-16 591 0.082564 2001-02-06 586 0.470872 2001-02-10 531 -0.536194 2001-02-16 586 0.949947 2001-02-19 530 -1.031167 2001-02-22 540 -1.827251 

Para responder a su pregunta real, haría esto (realmente no hay suficiente información, pero pondré algunas expectativas razonables):

  • No realice un bucle en las consultas, a menos que tenga un número muy pequeño de consultas absolutas
  • Lee la porción más grande en la memoria que puedas. Por lo general, esto se logra seleccionando los mayores rangos de datos que necesita, incluso si selecciona MÁS datos de los que realmente necesita.
  • Luego subseleccione usando expresiones en memoria, que generalmente serán órdenes de magnitud más rápidas.
  • Los elementos de la lista están limitados a aproximadamente 30 elementos en total (esto es un límite de implementación actual en el lado de PyTables). Funcionará si especifica más, pero lo que sucederá es que leerá una gran cantidad de datos y luego se volverá a indexar (en memoria). Así que el usuario debe ser consciente de esto.

Entonces, por ejemplo, digamos que tiene 1000 ID únicas con 10000 fechas por como lo demuestra mi ejemplo. Desea seleccionar, por ejemplo, 200 de estos, con un rango de fechas de 1000.

Entonces, en este caso, simplemente seleccionaría las fechas y luego haría la comparación en memoria, algo como esto:

 df = pd.read_hdf('test.h5','df',where='date=>global_start_date & date<=global_end_date') df[df.isin(list_of_ids)] 

También puede tener fechas que cambian por ids. Así que repártelos, esta vez usando una lista de identificadores.

Algo como esto:

 output = [] for i in len(list_of_ids) % 30: ids = list_of_ids[i:(i+30)] start_date = get_start_date_for_these_ids (global) end_date = get_end_date_for_these_ids (global) where = 'id=ids & start_date>=start_date & end_date<=end_date' df = pd.read_hdf('test.h5','df',where=where) output.append(df) final_result = concat(output) 

La idea básica es seleccionar un superconjunto de los datos utilizando los criterios que desee, subeleccionando para que quepa en la memoria, pero limite la cantidad de consultas que hace (por ejemplo, imagine que termina seleccionando una sola fila con su consulta, si tienes que consultar este 18M veces eso es malo).