2015-03-27 19 views
5

Mam poniższy kod, za pomocą którego mogę obliczyć średnią ważoną wolumenem cenę o trzy linie kodu Pandy.Panda Efektywna kalkulacja VWAP

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

Staram się znaleźć sposób, aby kod tego bez użycia cumsum() jako ćwiczenie. Próbuję znaleźć rozwiązanie, które daje jedną kolumnę VWAP. Próbowałem poniżej linii, używając .apply(). Ta logika istnieje, ale problem polega na tym, że nie mogę przechowywać wartości w wierszu n, aby użyć w wierszu (n + 1). Jak podejść do tego w pandas - wystarczy użyć zewnętrznej tuplet lub słownika do tymczasowego przechowywania łącznych wartości?

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) 

Czy istnieje jedno rozwiązanie rozwiązania powyższego problemu?

EDIT:

Moją główną motywacją jest, aby zrozumieć, co dzieje się pod maską. Jest to głównie ćwiczenie, niż jakikolwiek ważny powód. Wierzę, że każdy cumulus w serii o rozmiarze N ma złożoność czasu N (?). Zastanawiam się więc, czy zamiast obliczania dwóch oddzielnych kumulacji, możemy obliczyć oba w jednym przejściu - wzdłuż linii this. Bardzo chętnie przyjmuję odpowiedź na to - zamiast działającego kodu.

+0

Korzystanie z aplikacji będzie znacznie wolniejsze niż twoja pierwsza metoda, przy okazji – EdChum

+0

@EdChum, dziękuję, że masz alternatywne rozwiązanie bez użycia 'cumsum'? – Rhubarb

+0

Nie w tej chwili, cuma jest metodą wektorowaną, aplikacja nie pokona tego. – EdChum

Odpowiedz

8

Wejście w jedno przejście w jedną linię zaczyna się trochę semantyki. Co powiesz na rozróżnienie: możesz to zrobić za pomocą 1 linii pand, 1 linii numpy lub kilku linii numby.

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

Szybkie Edit: Chciałbym podziękować Janowi do oryginalnego postu :)

można uzyskać nawet szybsze wyniki według wersji @ JIT-ing NumPy za:

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

To dostało mi 50.9 µs per loop jako w stosunku do 74.5 µs per loop przy użyciu powyższej wersji vwap.

+1

Dzięki za poprawę! Ja tylko ustaliłem czas i nie uzyskałem tak dużego przyspieszenia, ale twoja droga jest zdecydowanie szybsza. Wydaje mi się, że numba lepiej radzi sobie z łączeniem z niezliczonymi z biegiem czasu. – JohnE