Выполнение rolling.apply
с несколькими столбцами (здесь X, y) в качестве входных данных и возвращение 3-х выходов невозможно с реализованными методами. Лучший способ - использовать метод roll от piRSquared.
from numpy.lib.stride_tricks import as_strided as stride
import pandas as pd
def roll(df, w, **kwargs):
v = df.values
d0, d1 = v.shape
s0, s1 = v.strides
a = stride(v, (d0 - (w - 1), w, d1), (s0, s0, s1))
rolled_df = pd.concat({
row: pd.DataFrame(values, columns=df.columns)
for row, values in zip(df.index[w-1:], a) #small difference to get the right date later
})
return rolled_df.groupby(level=0, **kwargs)
Затем задайте для функции apply
для каждого вида, чтобы получить результат из OLS
. Итак, вот как это сделать:
def result_tup (df_roll):
result = sm.OLS( df_roll['y'],
df_roll[['one','X']]).fit()
return ( df_roll.index.get_level_values(0)[-1], result.rsquared,
result.params[1], result.mse_resid)
Теперь вы хотите применить эту функцию к группам с 5-дневными интервалами, так что вы можете сделать:
# input and fix a seed for random
date_range=pd.date_range('2015-01-01','2019-12-31')
np.random.seed(1)
df=pd.DataFrame(np.random.rand(len(date_range),2),index=date_range,columns=['X','y'])
#the two parameters and add the column with a 1 instead of doing it each time with sm.add_constant
years_windows = 2
day_freq = 5
df['one'] = 1
#calculate the length of the window
len_window = len(pd.date_range(pd.Timestamp.today().date() - pd.DateOffset(years=2),
pd.Timestamp.today().date(), freq=f'{day_freq}D'))
# groupby every day_freq rows and do the calculation:
df_res = pd.concat([ pd.DataFrame( roll(dfg, len_window).apply(result_tup).tolist(),
columns=['date', 'RSQ', 'Beta','StdErr'])
for _, dfg in df.groupby(np.arange(len(df))%day_freq)])\
.set_index('date').sort_index()
#and apply the np.sqrt on the column:
df_res['StdErr'] = np.sqrt(df_res['StdErr'])
и вы получите способ быстрее:
RSQ Beta StdErr
date
2016-12-31 0.000107 0.010800 0.300927
2017-01-01 0.001380 0.036603 0.291804
2017-01-02 0.000870 -0.030364 0.294584
2017-01-03 0.003308 0.056052 0.280171
2017-01-04 0.005622 -0.081809 0.303257
... ... ... ...
2019-12-27 0.000147 0.012609 0.287182
2019-12-28 0.001144 -0.031921 0.268274
2019-12-29 0.000120 0.010720 0.289787
2019-12-30 0.000280 0.014995 0.278135
2019-12-31 0.018433 0.137605 0.293537