2015-10-30 14 views
6

Ho una configurazione semplice: dati di mercato (zecche) in un dataframe df panda in questo modo:accelerare le funzioni di aggregazione personalizzate

index period ask bid 
00:00:00.126 42125 112.118 112.117 
00:00:00.228 42125 112.120 112.117 
00:00:00.329 42125 112.121 112.120 
00:00:00.380 42125 112.123 112.120 
00:00:00.432 42125 112.124 112.121 
00:00:00.535 41126 112.124 112.121 
00:00:00.586 41126 112.122 112.121 
00:00:00.687 41126 112.124 112.121 
00:00:01.198 41126 112.124 112.120 
00:00:01.737 41126 112.124 112.121 
00:00:02.243 41126 112.123 112.121 

Ora uso pandas.groupy a periodi aggregati

g=df.groupby('period') 

È facile ottenere prezzi minimi e massimi per periodo, ad es

import numpy as np 
res=g.agg({'ask': [np.amax, np.amin]}) 

Anche questo è abbastanza veloce. Ora, voglio anche il primo e l'ultimo prezzo per periodo. Questo è dove iniziano i problemi. Naturalmente, non posso fare:

res=g.agg({'ask': lambda x: x[0]}) 

e funziona, in pratica, ma è terribilmente lento per grandi insiemi di dati. Fondamentalmente, l'overhead di chiamata per una chiamata di funzione Python è semplicemente enorme.

Qualcuno sa di una funzione numpy analoga a np.amax che restituirà il primo o l'ultimo elemento di un gruppo? Non sono riuscito a trovarne uno. iloc [0] non fa il trucco perché è un metodo di un oggetto e, quindi, non posso passarlo come una funzione a g.agg, perché non ho l'oggetto in questa fase (questo è ciò che il lambda è necessario per).

Ora, non sono pigro e ho provato a farlo da solo utilizzando cython.

import numpy as np 
cimport numpy as np 

cpdef double first(np.ndarray array_series): 
    return array_series[0] 

Ma panda non accettare questo come una funzione di aggregazione perché passa un pd.core.series-oggetto piuttosto che un np.ndarray. (Neppure uno deriva dall'altra, il compilatore non lo riconosce)

Qualcuno sa come scrivere una funzione cython che accetta una serie di panda senza il sovraccarico di chiamata Python?

+0

Hai provato 'df.groupby ('periodo') prima.() 'e' df.groupby ('periodo'). last() '? – EdChum

+0

Grazie, è un buon suggerimento. Funziona, ma non posso passare la funzione first() - g.agg (...), posso? Mi piacerebbe di più, perché vorrei applicare molte funzioni di aggregazione diverse contemporaneamente (amin, amax, first, ...). Sarà una soluzione temporanea per usarlo e quindi assemblare manualmente il mio set di dati finale, suppongo. – user5507059

+0

Sì, puoi, per favore vedi la mia risposta – EdChum

risposta

3

IIUC allora si può fare first e last:

In [270]: 
g=df.groupby('period') 
res=g.agg({'ask': [np.amax, np.amin, 'first', 'last']}) 
res 

Out[270]: 
      ask       
      amax  amin first  last 
period          
41126 112.124 112.122 112.124 112.123 
42125 112.124 112.118 112.118 112.124 
+0

Sei terrificante. Grazie!! – user5507059

+0

Ma facendo un passo avanti. Cosa succede se voglio una funzione di aggregazione personalizzata non standard. Posso criptarlo? – user5507059

+0

probabilmente ma non sono un esperto di cython – EdChum

1

Un'alternativa è quella di ricampionare semplicemente e utilizzare OHLC (open=first,close=last,high=max,low=min)

In [56]: df = DataFrame({'A' : np.arange(10), 'B' : pd.date_range('20130101',periods=5).tolist()*2}) 

In [57]: df 
Out[57]: 
    A   B 
0 0 2013-01-01 
1 1 2013-01-02 
2 2 2013-01-03 
3 3 2013-01-04 
4 4 2013-01-05 
5 5 2013-01-01 
6 6 2013-01-02 
7 7 2013-01-03 
8 8 2013-01-04 
9 9 2013-01-05 

In [58]: df.set_index('B').resample('D',how='ohlc') 
Out[58]: 
       A    
      open high low close 
B        
2013-01-01 0 5 0  5 
2013-01-02 1 6 1  6 
2013-01-03 2 7 2  7 
2013-01-04 3 8 3  8 
2013-01-05 4 9 4  9 
Problemi correlati