2013-06-25 14 views
5

Ho una serie temporale di diversi giorni di dati di 1 minuto e vorrei fare una media di tutti i giorni per ora del giorno.Modo più veloce per raggruppare l'ora del giorno in panda

Questo è molto 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() 

vuole quasi un minuto per correre!

Mentre qualcosa come:

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

richiede solo una frazione di secondo.

C'è un modo più veloce per raggruppare in base all'ora del giorno?

Qualche idea sul perché sia ​​così lento?

+0

dt.time non è ottimizzato dai panda. Ci vuole molto tempo per convertire un pandas TimeSeries in un array datetime.time. – waitingkuo

risposta

2

Sia il "lambda-versione" e la proprietà di tempo introdotta nel version 0.11 sembra essere lento nella versione 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 <type 'exceptions.RuntimeError'> ignored 
Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' in <type 'exceptions.RuntimeError'> ignored 
Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' in <type 'exceptions.RuntimeError'> ignored 
1 loops, best of 3: 11.8 s per loop 

Con il master attuale entrambi i metodi sono notevolmente più veloce:

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' 

Quindi puoi aggiornare ad un master o aspettare 0.11.1 che dovrebbe essere rilasciato questo mese.

+0

Qual è il tuo "ser"? È il mio "all_data"? Per me: ' version.version', '% timeit all_data.groupby. (Lambda x: x.time()) media() ',' % timeit all_data.groupby (all_data.index.time) .mean() ' Dà: ' '0.11.0'', '1 loop, meglio di 3: 21.2 s per loop', ' 1 loop, meglio di 3: 21.7 s per loop' ' – joeb1415

+0

@ joeb1415 aggiornato la mia risposta, sembra essere dovuto alla versione dei panda (i numeri sono cambiati un po 'da quando sono su un'altra macchina ora). "all_data" è il tuo "all_data". – bmu

2

È più veloce raggruppare gli attributi ora/minuto/... anziché .time. Ecco la linea di base di Jeff:

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

e senza tempo è molto più veloce (il meno attributi più velocemente si è):

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: gli oggetti di tempo non accettano un nanosecondo (ma questa è la risoluzione di DatetimeIndex).

Probabilmente dovremmo convertire l'indice di avere oggetti di tempo per rendere questo confronto equo:

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)) 

Quindi è circa 10 volte più veloce per la massima risoluzione, e si può facilmente rendere più grossolana (e più veloce) per esempio groupby solo l'ora e il minuto ..

Problemi correlati