Pandas 高效的 VWAP 计算

Pandas Efficient VWAP Calculation

我有下面的代码,使用它我可以通过三行 Pandas 代码计算成交量加权平均价格。

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

我正在尝试找到一种无需使用 cumsum() 作为练习来编写此代码的方法。我正在尝试找到一种解决方案,该解决方案一次性提供 VWAP 列。我尝试了下面的行,使用 .apply()。逻辑在那里,但问题是我无法在第 n 行中存储值以便在第 (n+1) 行中使用。您如何在 pandas 中处理此问题 - 仅使用外部连音符或字典临时存储累积值?

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)

上面的问题有没有一次性解决的方法?

编辑:

我的主要动机是了解幕后发生的事情。所以,它主要是为了锻炼而不是任何正当理由。我相信大小为 N 的 Series 上的每个 cumsum 的时间复杂度为 N(?)。所以我想知道,不是 运行 两个单独的 cumsum,我们能否一次计算两者 - 沿着 this 的路线。很高兴接受对此的回答 - 而不是工作代码。

进入一次通过与一行开始变得有点语义化。区别一下:你可以用 1 行 pandas、1 行 numpy 或几行 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()

时间安排:

%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

快速编辑:只想感谢 John 的原创 post :)

你可以通过@jit-ing numpy 的版本获得更快的结果:

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

这让我 50.9 µs per loop 而不是 74.5 µs per loop 使用上面的 vwap 版本。