Pandas Эффективный расчет VWAP

У меня есть приведенный ниже код, с помощью которого я могу рассчитать средневзвешенную цену по объему с помощью трех строк кода 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 имеет временную сложность N (?). Поэтому мне было интересно, вместо того, чтобы запускать два отдельных cumsum, можем ли мы вычислить оба за один проход - в соответствии с этим. Очень рад принять ответ на этот вопрос, а не рабочий код.


person Zhubarb    schedule 27.03.2015    source источник
comment
Кстати, использование apply будет значительно медленнее, чем ваш первый метод.   -  person EdChum    schedule 27.03.2015
comment
@EdChum, спасибо, у вас есть альтернативное решение без использования cumsum?   -  person Zhubarb    schedule 27.03.2015
comment
На данный момент нет, cumsum - это векторизованный метод, который не превзойдет это.   -  person EdChum    schedule 27.03.2015
comment
@JohnE, моя главная мотивация - понять, что происходит под капотом. Таким образом, это в основном для упражнений, чем по какой-либо уважительной причине. Я считаю, что каждый cumsum в серии размера N имеет временную сложность N. Поэтому мне было интересно, вместо запуска двух отдельных cumsum, можем ли мы вычислить оба за один проход - по строкам это. Очень рад принять ответ на этот вопрос, а не рабочий код.   -  person Zhubarb    schedule 27.03.2015


Ответы (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
person JohnE    schedule 27.03.2015

Быстрое редактирование: просто хотел поблагодарить Джона за оригинальный пост :)

Вы можете получить еще более быстрые результаты с помощью версии @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 выше.

person Ran Aroussi    schedule 31.12.2015
comment
Спасибо за улучшение! Я только что засекал время и не получил такого большого прироста скорости, но ваш способ определенно быстрее. Я думаю, что numba со временем стала лучше сочетаться с numpy. - person JohnE; 05.03.2016