Pandas.DataFrame rebanar con múltiples rangos de fechas

Tengo un objeto de dataframe indexado por fecha y hora con más de 100,000 filas. Me preguntaba si había una manera conveniente de usar pandas para obtener un subconjunto de este dataframe que se encuentra dentro de múltiples rangos de fechas.

Por ejemplo, digamos que tenemos dos rangos de fechas: (datetime.datetime(2016,6,27,0,0,0), datetime.datetime(2016,6,27,5,0,0)

y

(datetime.datetime(2016,6,27,15,0,0), datetime.datetime(2016,6,27,23,59,59)

Digamos que queremos obtener todas las filas de un objeto de dataframe que se encuentra ya sea en el primer rango de fechas o en el segundo rango de fechas, donde el objeto de dataframe tiene filas por cada segundo desde 2016-06-27 00:00:00 hasta 2016- 06-27 23:59:59. ¿Hay una manera fácil en los pandas para hacer esto?

¡Gracias por tu ayuda!

Hay dos formas principales de dividir un DataFrame con un DatetimeIndex por fecha.

  • por df.loc[start:end] : df.loc[start:end] . Si hay varios rangos de fechas, los segmentos individuales se pueden concatenar con pd.concat .

  • por máscara de selección booleana: df.loc[mask]


Usando pd.concat y rebanadas :

 import numpy as np import pandas as pd np.random.seed(2016) N = 10**2 df = pd.DataFrame(np.random.randint(10, size=(N, 2)), index=pd.date_range('2016-6-27', periods=N, freq='45T')) result = pd.concat([df.loc['2016-6-27':'2016-6-27 5:00'], df.loc['2016-6-27 15:00':'2016-6-27 23:59:59']]) 

rendimientos

  0 1 2016-06-27 00:00:00 0 2 2016-06-27 00:45:00 5 5 2016-06-27 01:30:00 9 6 2016-06-27 02:15:00 8 4 2016-06-27 03:00:00 5 0 2016-06-27 03:45:00 4 8 2016-06-27 04:30:00 7 0 2016-06-27 15:00:00 2 5 2016-06-27 15:45:00 6 7 2016-06-27 16:30:00 6 8 2016-06-27 17:15:00 5 1 2016-06-27 18:00:00 2 9 2016-06-27 18:45:00 9 1 2016-06-27 19:30:00 9 7 2016-06-27 20:15:00 3 6 2016-06-27 21:00:00 3 5 2016-06-27 21:45:00 0 8 2016-06-27 22:30:00 5 6 2016-06-27 23:15:00 0 8 

Tenga en cuenta que, a diferencia de la mayoría de las syntax de segmentación utilizadas en Python,

 df.loc['2016-6-27':'2016-6-27 5:00'] 

Es inclusivo en ambos extremos: la división define un intervalo cerrado, no es un intervalo medio abierto.


Usando una máscara de selección booleana:

 mask = (((df.index >= '2016-6-27') & (df.index <= '2016-6-27 5:00')) | ((df.index >= '2016-6-27 15:00') & (df.index < '2016-6-28'))) result2 = df.loc[mask] assert result.equals(result2) 

Siento que la mejor opción será usar los controles directos en lugar de usar la función loc:

 df = df[((df.index >= '2016-6-27') & (df.index <= '2016-6-27 5:00')) | ((df.index >= '2016-6-27 15:00') & (df.index < '2016-6-28'))] 

Esto funciona para mi.

El principal problema con la función loc con un segmento es que los límites deben estar presentes en los valores reales, de lo contrario, esto generará KeyError.