2013-10-01 3 views
8

Я пытаюсь рассчитать средневзвешенную цену по объему.Использование функции roll_apply на объекте DataFrame

Чтобы сделать это, у меня есть функция VWAP, что делает это для меня, как так:

def vwap(bars): 
    return ((bars.Close*bars.Volume).sum()/bars.Volume.sum()).round(2) 

Когда я пытаюсь использовать эту функцию с rolling_apply, как показано на рисунке, я получаю сообщение об ошибке:

import pandas.io.data as web 
bars = web.DataReader('AAPL','yahoo') 
print pandas.rolling_apply(bars,30,vwap) 

AttributeError: 'numpy.ndarray' object has no attribute 'Close' 

Ошибка имеет смысл для меня, потому что roll_apply не требует DataSeries или ndarray как входной, а не dataFrame .. то, как я это делаю.

Есть ли способ использовать roll_apply для DataFrame для решения моей проблемы?

ответ

9

Это непосредственно не включен, но вы можете сделать это, как этот

In [29]: bars 
Out[29]: 
<class 'pandas.core.frame.DataFrame'> 
DatetimeIndex: 942 entries, 2010-01-04 00:00:00 to 2013-09-30 00:00:00 
Data columns (total 6 columns): 
Open   942 non-null values 
High   942 non-null values 
Low   942 non-null values 
Close  942 non-null values 
Volume  942 non-null values 
Adj Close 942 non-null values 
dtypes: float64(5), int64(1) 

window=30 

In [30]: concat([ (Series(vwap(bars.iloc[i:i+window]), 
         index=[bars.index[i+window]])) for i in xrange(len(df)-window) ]) 
Out[30]: 
2010-02-17 203.21 
2010-02-18 202.95 
2010-02-19 202.64 
2010-02-22 202.41 
2010-02-23 202.19 
2010-02-24 201.85 
2010-02-25 201.65 
2010-02-26 201.50 
2010-03-01 201.31 
2010-03-02 201.35 
2010-03-03 201.42 
2010-03-04 201.09 
2010-03-05 200.95 
2010-03-08 201.50 
2010-03-09 202.02 
... 
2013-09-10 485.94 
2013-09-11 487.38 
2013-09-12 486.77 
2013-09-13 487.23 
2013-09-16 487.20 
2013-09-17 486.09 
2013-09-18 485.52 
2013-09-19 485.30 
2013-09-20 485.37 
2013-09-23 484.87 
2013-09-24 485.81 
2013-09-25 486.41 
2013-09-26 486.07 
2013-09-27 485.30 
2013-09-30 484.74 
Length: 912 
+1

Хорошее решение, было полезно для меня! Вопрос: В вашем понимании списка вы бы не использовали bars.iloc [i: i + window + 1], поскольку .iloc исключает верхнюю границу? В вашем коде только 29 значений используются в вычислении, заканчивающемся на bars.iloc [i + window-1], в то время как bar.index [i + window] используется как метка. При таком расчете я бы подумал, что вы хотите, чтобы в расчет включались строки bar.iloc [i + window]. – geronimo

4

A очищены версию для справки, надеюсь, получили индексацию правильно:

def myrolling_apply(df, N, f, nn=1): 
    ii = [int(x) for x in arange(0, df.shape[0] - N + 1, nn)] 
    out = [f(df.iloc[i:(i + N)]) for i in ii] 
    out = pandas.Series(out) 
    out.index = df.index[N-1::nn] 
    return(out) 
1

Modified @ ответ mathtick, чтобы включить na_fill. Также обратите внимание, что вашей функции f необходимо вернуть одно значение, это не может вернуть dataframe с несколькими столбцами.

def rolling_apply_df(dfg, N, f, nn=1, na_fill=True): 
    ii = [int(x) for x in np.arange(0, dfg.shape[0] - N + 1, nn)] 
    out = [f(dfg.iloc[i:(i + N)]) for i in ii] 
    if(na_fill): 
     out = pd.Series(np.concatenate([np.repeat(np.nan, N-1),np.array(out)])) 
     out.index = dfg.index[::nn] 
    else: 
     out = pd.Series(out) 
     out.index = dfg.index[N-1::nn] 
    return(out) 
Смежные вопросы