2015-03-27 9 views
5

Ich habe den folgenden Code, mit dem ich den volumengewichteten Durchschnittspreis durch drei Zeilen Pandas-Code berechnen kann.Pandas Efficient VWAP Berechnung

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'] 

Ich versuche, einen Weg zu finden, dies als eine Übung ohne cumsum() zu codieren. Ich versuche, eine Lösung zu finden, die die VWAP Spalte in einem Durchgang gibt. Ich habe die untere Zeile mit .apply() versucht. Die Logik ist da, aber das Problem ist, dass ich keine Werte in Zeile n speichern kann, um in Zeile (n + 1) zu verwenden. Wie geht man das in pandas an - verwenden Sie einfach eine externe Tuplete oder ein Wörterbuch für temporäre Speicherung von kumulativen Werten?

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) 

Gibt es eine One-Pass-Lösung für das oben genannte Problem?

EDIT:

Meine Hauptmotivation ist zu verstehen, was unter der Haube geschieht. Also, es ist hauptsächlich für Übung als irgendeinen gültigen Grund. Ich glaube, jeder Cumsum auf einer Serie der Größe N hat eine Zeitkomplexität N (?). Also habe ich mich gefragt, anstatt zwei separate Cumsums zu fahren, können wir beide in einem Durchgang berechnen - in der Richtung von this. Sehr gerne eine Antwort darauf zu akzeptieren - anstatt Code zu arbeiten.

+0

Verwenden Sie anwenden wird wesentlich langsamer als Ihre erste Methode übrigens – EdChum

+0

@EdChum, danke, haben Sie eine alternative Lösung ohne Verwendung von 'Cumsum'? – Rhubarb

+0

Nicht im Moment, Cumsum ist eine vektorisierte Methode anwenden wird dies nicht schlagen. – EdChum

Antwort

8

In einen Durchgang gegen eine Zeile zu kommen beginnt ein wenig semantisch zu werden. Wie wäre es damit für eine Unterscheidung: Sie können es mit 1 Linie von Pandas, 1 Zeile von numpy oder mehreren Zeilen von numba tun.

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

Quick Edit: Ich wollte nur John für den ursprünglichen Beitrag :) kann

Sie erhalten von @ jit-ing numpy Version noch schneller Ergebnisse danken:

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

Das hat mich 50.9 µs per loop als o. Bekommen posed to 74.5 µs per loop mit der vwap-Version oben.

+1

Danke für die Verbesserung! Ich habe es nur selbst getimt und nicht ganz so schnell beschleunigt, aber dein Weg ist definitiv schneller. Ich denke, dass sich numba im Laufe der Zeit immer besser mit der Anzahl der Spieler verbunden hat. – JohnE

Verwandte Themen