Pandas 高效的 VWAP 计算
Posted
技术标签:
【中文标题】Pandas 高效的 VWAP 计算【英文标题】:Pandas Efficient VWAP Calculation 【发布时间】:2015-05-31 16:03:52 【问题描述】:我有下面的代码,使用它我可以通过三行 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 的系列上的每个 cumsum 的时间复杂度为 N(?)。所以我想知道,不是运行两个单独的 cumsum,我们可以一次计算两者 - 沿着this 的行。很高兴接受这个答案 - 而不是工作代码。
【问题讨论】:
顺便说一句,使用 apply 会比你的第一种方法慢很多 @EdChum,谢谢你有不使用cumsum
的替代解决方案吗?
目前不是, cumsum 是一种矢量化方法 apply 不会打败这个。
@JohnE,我的主要动机是了解幕后发生的事情。所以,它主要是为了锻炼而不是任何正当理由。我相信大小为 N 的系列上的每个 cumsum
具有时间复杂度 N。所以我想知道,与其运行两个单独的 cumsum
,不如我们可以一次计算两者 - 沿着 this 的行。很高兴接受这个答案 - 而不是工作代码。
【参考方案1】:
快速编辑:只是想感谢约翰的原始帖子:)
@jit-ing numpy 的版本你可以得到更快的结果:
@jit
def np_vwap():
return np.cumsum(v*(h+l)/2) / np.cumsum(v)
这让我得到了50.9 µs per loop
,而不是使用上面的 vwap 版本的74.5 µs per loop
。
【讨论】:
感谢改进!我只是自己计时,并没有得到那么大的速度提升,但你的方式肯定更快。随着时间的推移,我认为 numba 在与 numpy 结合方面做得更好。【参考方案2】:单程与单行开始变得有点语义化。怎么样区分一下:你可以用 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
【讨论】:
以上是关于Pandas 高效的 VWAP 计算的主要内容,如果未能解决你的问题,请参考以下文章
许多数据帧上的高效 Python Pandas 股票 Beta 计算
在pandas中使用query替代loc进行高效简洁的条件筛选
在pandas中使用query替代loc进行高效简洁的条件筛选