2015-05-15 35 views
10

Sto tentando di utilizzare Cython per accelerare un calcolo di Pandas DataFrame che è relativamente semplice: iterando su ogni riga in DataFrame, aggiungi quella riga a se stessa ea tutte le righe rimanenti in DataFrame, sommi questi attraverso ogni riga e produci la lista di queste somme. La lunghezza di queste serie diminuirà quando le righe nel DataFrame saranno esaurite. Queste serie sono memorizzate come un dizionario digitato sul numero di riga dell'indice.Come applicare Cython a Pandas DataFrame

def foo(df): 
    vals = {i: (df.iloc[i, :] + df.iloc[i:, :]).sum(axis=1).values.tolist() 
      for i in range(df.shape[0])} 
    return vals 

Oltre ad aggiungere %%cython nella parte superiore di questa funzione, qualcuno ha una raccomandazione su come mi piacerebbe andare sull'utilizzo cdefs per convertire i valori dataframe a doppie e quindi cythonize questo codice?

Di seguito alcuni dati dummy:

>>> df 

      A   B   C   D   E 
0 -0.326403 1.173797 1.667856 -1.087655 0.427145 
1 -0.797344 0.004362 1.499460 0.427453 -0.184672 
2 -1.764609 1.949906 -0.968558 0.407954 0.533869 
3 0.944205 0.158495 -1.049090 -0.897253 1.236081 
4 -2.086274 0.112697 0.934638 -1.337545 0.248608 
5 -0.356551 -1.275442 0.701503 1.073797 -0.008074 
6 -1.300254 1.474991 0.206862 -0.859361 0.115754 
7 -1.078605 0.157739 0.810672 0.468333 -0.851664 
8 0.900971 0.021618 0.173563 -0.562580 -2.087487 
9 2.155471 -0.605067 0.091478 0.242371 0.290887 

e output previsto:

>>> foo(df) 

{0: [3.7094795101205236, 
    2.8039983729106, 
    2.013301815968468, 
    2.24717712931852, 
    -0.27313665495940964, 
    1.9899718844711711, 
    1.4927321304935717, 
    1.3612155622947018, 
    0.3008239883773878, 
    4.029880107986906], 

. . . 

6: [-0.72401524913338, 
    -0.8555318173322499, 
    -1.9159233912495635, 
    1.813132728359954], 
7: [-0.9870483855311194, -2.047439959448434, 1.6816161601610844], 
8: [-3.107831533365748, 0.6212245862437702], 
9: [4.350280705853288]} 
+1

La mia sensazione è che non si otterrà una quantità enorme - la maggior parte del lavoro è nell'aggiunta (vettoriale, float + array) o nella somma. Entrambi rimangono come in Cython. Potresti ottenere un accelerazione (non basata su Cython) eseguendo la 'sum (axis = 1)' una volta fuori dal ciclo. – DavidW

+0

Non è possibile lavorare direttamente con dataframes/series in cython, ma si dovrà lavorare con l'array numpy sottostante. Vedi qui per un tutorial: http://pandas.pydata.org/pandas-docs/stable/enhancingperf.html – joris

risposta

13

Se stai solo cercando di farlo più velocemente e non specificamente utilizzando Cython, avevo appena farlo in semplice numpy (circa 50 volte più veloce).

def numpy_foo(arr): 
    vals = {i: (arr[i, :] + arr[i:, :]).sum(axis=1).tolist() 
      for i in range(arr.shape[0])} 
    return vals 

%timeit foo(df) 
100 loops, best of 3: 7.2 ms per loop 

%timeit numpy_foo(df.values) 
10000 loops, best of 3: 144 µs per loop 

foo(df) == numpy_foo(df.values) 
Out[586]: True 

In generale, i panda ti dà un sacco di comodità relativi a NumPy, ma ci sono i costi generali. Quindi, in situazioni in cui i panda non aggiungono realmente nulla, generalmente puoi accelerare le cose facendo in modo che diventino insensibili. Per un altro esempio, vedere questo question che ho chiesto che ha mostrato una differenza di velocità approssimativamente paragonabile (circa 23x).