Для uni-проекта я пытаюсь выполнить скользящую множественную регрессию по каждому столбцу фрейма данных (зависимые переменные) по трем факторам (независимые переменные). Столбцы зависимых данных - это акции, которые я обозначил числами. Теперь мои данные не очень чистые, потому что некоторые столбцы (запасы) df_dependent данных содержат значения NaN, но только в начале. Чтобы показать, как выглядит моя исходная ситуация, я создал следующий пример:
# specify columns and index
col = [str(item) for item in range(40)]
ind = pd.date_range("20170101", periods=300)
# build random df (dependent data for regression)
df_dependent = pd.DataFrame(np.random.randn(300, 40), columns=col, index = ind)
# random instances of NaN
for i in range(5):
df_dependent[str(random.randint(0, 40))].iloc[:20] = np.NaN
#build second random df (independent data for regression)
df_independent = df = pd.DataFrame(np.random.randn(300, 3), columns=["A", "B", "C"], index = ind)
# add constant
df_independent = sm.add_constant(df_independent)
Теперь я хочу регрессировать df_dependent по df_independent в скользящем окне и сохранить его в словаре, где каждый ключ является одним из названия столбцов (акции) со всеми результатами регрессии. Мне удалось найти результат, который делает именно то, что я хочу, но, к сожалению, очень медленный, особенно при использовании фреймов данных большего размера, чем представлено здесь. Однако мое рабочее решение:
def multiple_rolling_regression_calc(df_dep, df_ind):
# preparing empty dictionary and dataframes inside dictionary
dic_regression = {}
dates = df_dep.index.tolist()
stock_list = df_dep.columns.tolist()
# shell used for making sure that stocks beginning with a NaN series (see above) have same shape
shell = pd.DataFrame(index = dates)
# fill empty dictionary with dataframes, loop through stocks
for k in stock_list:
# adjust endog for no NaN
df_dep_new = pd.DataFrame()
df_dep_new[k] = df_dep[k][df_dep[k].notna()]
# adjust exog to shape of endog_new
df_ind_new = pd.DataFrame()
df_ind_new = df_ind.loc[df_dep_new[k].index]
# Regression calculation
rols = RollingOLS(df_dep_new[k], df_ind_new, window = 21)
rres = rols.fit()
# Prepare empty dataframe with columns / regression output of interest
df_res = pd.DataFrame(columns = ["const", "A Beta", "B Beta", "C Beta", "R Squared", "N"])
# save regression output in empty dataframe which is in dictionary
df_res[["const", "A Beta", "B Beta", "C Beta"]] = rres.params
df_res["R Squared"] = rres.rsquared
df_res["N"] = rres.nobs
#merge with a dataframe with the correct form (add NaNs)
df_res = df_res.combine_first(shell)
df_res[df_res["N"] != 21] = np.NaN
# save df in dictionary under k (key = column name from df_dep)
dic_regression[k] = df_res
return dic_regression
result = multiple_rolling_regression_calc(df_dependent, df_independent)
Теперь я пробовал разные варианты этого кода, но не смог найти способ значительно повысить производительность. Вот почему я хотел спросить, есть ли у кого-нибудь идея или совет, как сделать этот расчет быстрее. Я слышал о временном изменении фреймов данных на массивы numpy для повышения производительности, но я не знаю, возможно ли это в данном конкретном случае.