2014-06-13 14 views
7

Ho un dataframe con coordinate pixel consecutive in righe e colonne 'xpos', 'ypos' e voglio calcolare l'angolo in gradi di ogni percorso tra pixel consecutivi. Attualmente ho la soluzione presentata di seguito, che funziona bene e per la dimensione del mio file è abbastanza veloce, ma l'iterazione attraverso tutte le righe sembra non essere il modo per farlo. So come applicare una funzione a colonne diverse e come applicare le funzioni a diverse righe di colonne, ma non riesco a capire come combinarle entrambe.i panda applicano la funzione a più colonne e più righe

ecco il mio codice:

fix_df = pd.read_csv('fixations_out.csv') 

# wyliczanie kąta sakady 
temp_list=[] 
for count, row in df.iterrows(): 
    x1 = row['xpos'] 
    y1 = row['ypos'] 
    try: 
     x2 = df['xpos'].ix[count-1] 
     y2 = df['ypos'].ix[count-1] 
     a = abs(180/math.pi * math.atan((y2-y1)/(x2-x1))) 
     temp_list.append(a) 
    except KeyError: 
     temp_list.append(np.nan) 

e poi inserire la lista di temperatura in df

EDIT: dopo aver implementato la punta dal commento che ho:

df['diff_x'] = df['xpos'].shift() - df['xpos'] 
df['diff_y'] = df['ypos'].shift() - df['ypos'] 

def calc_angle(x): 
    try: 
     a = abs(180/math.pi * math.atan((x.diff_y)/(x.diff_x))) 
     return a 
    except ZeroDivisionError: 
     return 0 

df['angle_degrees'] = df.apply(calc_angle, axis=1) 

ho confrontato i il tempo di tre soluzioni per il mio df (la dimensione del df è di circa 6k di righe), l'iterazione è quasi 9 volte più lenta di quella applicata, e circa 1500 volte più lenta di allora enza applica:

tempo di esecuzione della soluzione di iterazione, compresa inserimento di una nuova colonna ritorna df: 1,51s

tempo di esecuzione della soluzione senza iterazione, con diffusa: 0.17s

tempo

esecuzione di risposta accettata da EdChum utilizzando diff(), senza iterazione e senza applicare: 0.001s

suggerimento: nON utilizzare iterazione o applicare e alwa cercate di utilizzare il calcolo vettoriale;) non solo è più veloce, ma anche più leggibile.

+1

Per iniziare è possibile calcolare la differenza come 'df ['xpos'].shift() - df ['xpos'] 'invece di fare questa riga, allora puoi calcolare l'angolo usando la tua funzione sull'intera colonna – EdChum

+0

Ho aggiornato la mia risposta ottengo meno di 1ms di performance che è molti ordini di magnitudine più veloce – EdChum

risposta

8

Puoi farlo tramite il seguente metodo e ho paragonato il modo dei panda al tuo modo ed è oltre 1000 volte più veloce, e cioè senza aggiungere l'elenco come una nuova colonna! Ciò è stato fatto su un 10000 fila dataframe

In [108]: 

%%timeit 
import numpy as np 
df['angle'] = np.abs(180/math.pi * np.arctan(df['xpos'].shift() - df['xpos']/df['ypos'].shift() - df['ypos'])) 

1000 loops, best of 3: 1.27 ms per loop 

In [100]: 

%%timeit 
temp_list=[] 
for count, row in df.iterrows(): 
    x1 = row['xpos'] 
    y1 = row['ypos'] 
    try: 
     x2 = df['xpos'].ix[count-1] 
     y2 = df['ypos'].ix[count-1] 
     a = abs(180/math.pi * math.atan((y2-y1)/(x2-x1))) 
     temp_list.append(a) 
    except KeyError: 
     temp_list.append(np.nan) 
1 loops, best of 3: 1.29 s per loop 

anche, se possibile, evitare di utilizzare apply, in quanto questo funziona riga-saggio, se si può trovare un metodo Vectorised in grado di lavorare su tutta la serie o dataframe poi sempre preferire questo.

UPDATE

visto che si sta solo facendo una sottrazione dalla riga precedente si è costruito nel metodo per questo diff questo si traduce in codice ancora più veloce:

In [117]: 

%%timeit 
import numpy as np 
df['angle'] = np.abs(180/math.pi * np.arctan(df['xpos'].diff(1)/df['ypos'].diff(1))) 

1000 loops, best of 3: 1.01 ms per loop 

Un altro aggiornamento

Esiste anche un metodo build in per la divisione serie e dataframe, questo ora fa più tempo e off b 1ms tempo:

In [9]: 

%%timeit 
import numpy as np 
df['angle'] = np.abs(180/math.pi * np.arctan(df['xpos'].diff(1).div(df['ypos'].diff(1)))) 

1000 loops, best of 3: 951 µs per loop 
+0

'abs' dovrebbe essere' np.abs' nel primo caso? – joris

+0

@joris, sì per coerenza ma ha fatto poca differenza 1.27ms contro 1.29 ms, aggiornerò la risposta, grazie, grazie – EdChum

Problemi correlati