Manera más rápida de agrupar por hora del día en pandas.

Tengo una serie de tiempo de varios días de datos de 1 minuto, y me gustaría promediar todos los días según la hora del día.

Esto es muy lento:

from datetime import datetime from pandas import date_range, Series time_ind = date_range(datetime(2013, 1, 1), datetime(2013, 1, 10), freq='1min') all_data = Series(randn(len(time_ind)), time_ind) time_mean = all_data.groupby(lambda x: x.time()).mean() 

Tarda casi un minuto en correr!

Mientras algo como:

 time_mean = all_data.groupby(lambda x: x.minute).mean() 

Solo toma una fracción de segundo.

¿Hay una forma más rápida de agrupar por hora del día?

¿Alguna idea de por qué esto es tan lento?

Tanto su “versión lambda” como la propiedad de tiempo introducidas en la versión 0.11 parecen ser lentas en la versión 0.11.0:

 In [4]: %timeit all_data.groupby(all_data.index.time).mean() 1 loops, best of 3: 11.8 s per loop In [5]: %timeit all_data.groupby(lambda x: x.time()).mean() Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' in  ignored Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' in  ignored Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' in  ignored 1 loops, best of 3: 11.8 s per loop 

Con el maestro actual ambos métodos son considerablemente más rápidos:

 In [1]: pd.version.version Out[1]: '0.11.1.dev-06cd915' In [5]: %timeit all_data.groupby(lambda x: x.time()).mean() 1 loops, best of 3: 215 ms per loop In [6]: %timeit all_data.groupby(all_data.index.time).mean() 10 loops, best of 3: 113 ms per loop '0.11.1.dev-06cd915' 

Por lo tanto, puede actualizar a un maestro o esperar a la versión 0.11.1 que se lanzará este mes.

Es más rápido agrupar por hora / minuto / .. atributos en lugar de .time . Aquí está la línea de base de Jeff:

 In [11]: %timeit all_data.groupby(all_data.index.time).mean() 1 loops, best of 3: 202 ms per loop 

y sin tiempo es mucho más rápido (cuantos menos atributos más rápido sea):

 In [12]: %timeit all_data.groupby(all_data.index.hour).mean() 100 loops, best of 3: 5.53 ms per loop In [13]: %timeit all_data.groupby([all_data.index.hour, all_data.index.minute, all_data.index.second, all_data.index.microsecond]).mean() 10 loops, best of 3: 20.8 ms per loop 

Nota: los objetos de tiempo no aceptan un nanosegundo (pero esa es la resolución de DatetimeIndex).

Probablemente deberíamos convertir el índice para tener objetos de tiempo para que esta comparación sea justa:

 In [21]: res = all_data.groupby([all_data.index.hour, all_data.index.minute, all_data.index.second, all_data.index.microsecond]).mean() In [22]: %timeit res.index.map(lambda t: datetime.time(*t)) 1000 loops, best of 3: 1.39 ms per loop In [23]: res.index = res.index.map(lambda t: datetime.time(*t)) 

Por lo tanto, es aproximadamente 10 veces más rápido para una resolución máxima, y ​​puede hacerlo fácilmente más grueso (y más rápido), por ejemplo, agrupando solo la hora y los minutos.