Voglio fare un calcolo "strano" su un DataFrame (potrebbe essere pensato come una serie) nei panda. DataFrame deve essere considerato come una serie temporale o simile (l'ordine degli elementi è importante).vectorizing forward-looking function pandas dataframe
- dato un valore di indice [i] (valore [i])
- Dato un gradino (ad esempio 1) [un numero intero o reale numero]
- Data una rr moltiplicatore (ad esempio 2) [un numero intero o reale]
Aspetto avanti a elementi [i:] e assegnare valore [i] una "classe" di:
- +1 se la en valori fanno causa raggiungono un livello di valore [i] + step * rr prima raggiungimento del valore [i] - passo
- -1 se i valori successivi raggiungono un livello di valore [i] - passo * rr prima valore raggiungimento [i] + step
- 0 negli altri casi (es. quando i valori risultanti toccano il valore [i] - passaggio e quindi valore [i] + passaggio o viceversa.
So che sembra assurdo. Immagina una passeggiata casuale con passi + 1/-1. Una sequenza come:
- 0, 1, verrà assegnato alla classe 1 2 (che può anche essere 0, 1, 0, 0, 1, 1, 0, 1, 1, 2)
- 0, -1, -2 saranno assegnati alla classe -1 (può anche essere 0, -1, 0, 0, 0, -1, -1, -1, -2)
- 0, + 1, 0, -1 o 0, -1, 0, 0, -1, 0, 1 e simili saranno di classe 0.
L'ho risolto il "classico" (e forse non così-pitonico) modo definendo una funzione:
import numpy as np
import pandas as pd
def FindClass(inarr, i=0, step=0.001, rr=2):
j = 0
foundClass = None
while i+j < len(inarr) - 1:
j += 1
if inarr[i+j] >= inarr[i] + step:
direction = 1
break
if inarr[i+j] <= inarr[i] - step:
direction = -1
break
while i+j < len(inarr)-1:
j += 1
if direction == 1 and inarr[i+j] >= inarr[i] + (step * rr):
foundClass = 1
break
elif direction == 1 and inarr[i+j] <= inarr[i] - step:
foundClass = 0
break
elif direction == -1 and inarr[i+j] <= inarr[i] - (step * rr):
foundClass = -1
break
elif direction == -1 and inarr[i+j] >= inarr[i] + step:
foundClass = 0
break
if foundClass is None:
foundClass = np.nan
return foundClass
e poi iterando su di esso:
if __name__ == "__main__":
steps = np.random.randint(-1, 2, size= 10000)
randomwalk = steps.cumsum(0)
rc = pd.DataFrame({'rw':randomwalk, 'result': np.nan})
for c in range(0, len(rc)-1):
rc.result[c] = FindClass(rc.rw, i=c, step=1)
print rc
sul mio portatile (e l'esecuzione di python 2.7) ottengo un profiling, che non è "troppo" male per una serie 10000 elementi:
python -m cProfile -s cumulative fbmk.py
<class 'pandas.core.frame.DataFrame'>
Int64Index: 10000 entries, 0 to 9999
Data columns (total 2 columns):
result 9996 non-null values
rw 10000 non-null values
dtypes: float64(1), int32(1)
932265 function calls (929764 primitive calls) in 2.643 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.106 0.106 2.646 2.646 fbmk.py:1(<module>)
9999 0.549 0.000 1.226 0.000 fbmk.py:4(FindClass)
158062 0.222 0.000 0.665 0.000 series.py:616(__getitem__)
2 0.029 0.014 0.561 0.281 __init__.py:3(<module>)
158062 0.226 0.000 0.443 0.000 index.py:718(get_value)
19998 0.070 0.000 0.442 0.000 frame.py:2082(__getattr__)
19998 0.111 0.000 0.331 0.000 frame.py:1986(__getitem__)
La domanda è:
Qualcuno vede una possibilità di vettorizzazione di questa funzione in panda/numpy in un modo che sta migliorando le prestazioni?
Se la cosa è fattibile con meno sforzi in R, sarebbe anche bello!
Grazie mille in anticipo!
Non è vettorializzare, ma forse è possibile scrivere la funzione 'findClass' in cython? – joris
Sì, certo che questa è una possibilità. La domanda qui è dovuta principalmente al fatto che si tratta di un'operazione ripetitiva riga per fila, e la gente di solito dice che con i panda e simili devi "pensare in vettoriale", evitando i loop ... Ho provato, ma non ho gestito ! – user3562348
Oltre alla mia idea nella mia risposta, penso che otterresti una notevole velocità dalla riscrittura delle tue funzioni per sfruttare i condizionali. Stai inserendo condizionali lunghi in un ciclo while, ma la tua logica ti consente di escludere molte delle opzioni il più delle volte. Ciò causerà molto meno codice da eseguire e probabilmente ti porterà un fattore 2-4 nel tempo di esecuzione. –