2015-03-27 5 views
5

Ho il codice seguente, con il quale posso calcolare il prezzo medio ponderato per il volume di tre righe di codice Panda.Pandas Calcolo VWAP efficiente

import numpy as np 
import pandas as pd 
from pandas.io.data import DataReader 
import datetime as dt 

df = DataReader(['AAPL'], 'yahoo', dt.datetime(2013, 12, 30), dt.datetime(2014, 12, 30)) 
df['Cum_Vol'] = df['Volume'].cumsum() 
df['Cum_Vol_Price'] = (df['Volume'] * (df['High'] + df['Low'] + df['Close']) /3).cumsum() 
df['VWAP'] = df['Cum_Vol_Price']/df['Cum_Vol'] 

Sto cercando di trovare un modo per codificare questo senza usare cumsum() come un esercizio. Sto cercando di trovare una soluzione che dia la colonna VWAP in un unico passaggio. Ho provato la riga sottostante, usando .apply(). La logica è lì, ma il problema è che non sono in grado di memorizzare i valori nella riga n per poterli utilizzare nella riga (n + 1). Come ci si avvicina a questo in pandas - basta usare un gruppo o un dizionario esterno per la memorizzazione temporanea di valori cumulativi?

df['Cum_Vol']= np.nan 
df['Cum_Vol_Price'] = np.nan 
# calculate running cumulatives by apply - assume df row index is 0 to N 
df['Cum_Vol'] = df.apply(lambda x: df.iloc[x.name-1]['Cum_Vol'] + x['Volume'] if int(x.name)>0 else x['Volume'], axis=1) 

Esiste una soluzione a un passaggio per il problema precedente?

EDIT:

La mia motivazione principale è quello di capire cosa sta succedendo sotto il cofano. Quindi, è principalmente per l'esercizio di qualsiasi motivo valido. Credo che ogni cumsum su una serie di dimensioni N abbia una complessità temporale N (?). Quindi mi stavo chiedendo, invece di eseguire due cumsum separati, possiamo calcolare entrambi in un solo passaggio - lungo le linee di this. Molto felice di accettare una risposta a questo - piuttosto che un codice funzionante.

+0

L'utilizzo di apply sarà notevolmente più lento del primo metodo dal modo in cui – EdChum

+0

@EdChum, grazie hai una soluzione alternativa senza usare 'cumsum'? – Rhubarb

+0

Non al momento, cumsum è un metodo vettorizzato applicato non batterà questo. – EdChum

risposta

8

Entrare in un passaggio contro una linea inizia a diventare un po 'semantica. Che ne dici di questo per una distinzione: puoi farlo con 1 riga di panda, 1 riga di numpy o più righe di numba.

from numba import jit 

df=pd.DataFrame(np.random.randn(10000,3), columns=['v','h','l']) 

df['vwap_pandas'] = (df.v*(df.h+df.l)/2).cumsum()/df.v.cumsum() 

@jit 
def vwap(): 
    tmp1 = np.zeros_like(v) 
    tmp2 = np.zeros_like(v) 
    for i in range(0,len(v)): 
     tmp1[i] = tmp1[i-1] + v[i] * (h[i] + l[i])/2. 
     tmp2[i] = tmp2[i-1] + v[i] 
    return tmp1/tmp2 

v = df.v.values 
h = df.h.values 
l = df.l.values 

df['vwap_numpy'] = np.cumsum(v*(h+l)/2)/np.cumsum(v) 

df['vwap_numba'] = vwap() 

Timings:

%timeit (df.v*(df.h+df.l)/2).cumsum()/df.v.cumsum() # pandas 
1000 loops, best of 3: 829 µs per loop 

%timeit np.cumsum(v*(h+l)/2)/np.cumsum(v)   # numpy 
10000 loops, best of 3: 165 µs per loop 

%timeit vwap()           # numba 
10000 loops, best of 3: 87.4 µs per loop 
3

Modifica rapida: Volevo solo ringraziare John per il post originale :)

si possono ottenere risultati ancora più veloce di versione @ JIT-zione di NumPy:

@jit def np_vwap(): return np.cumsum(v*(h+l)/2)/np.cumsum(v)

Questo mi ha dato 50.9 µs per loop come o pposed to 74.5 µs per loop utilizzando la versione vwap sopra.

+1

Grazie per il miglioramento! L'ho appena programmato da solo e non ho ottenuto un aumento della velocità abbastanza grande, ma la tua strada è decisamente più veloce. Penso che numba sia migliorata nel combinarsi con il tempo nel tempo. – JohnE