скользящий, расчет множественной регрессии очень медленный в pandas - PullRequest
0 голосов
/ 07 августа 2020

Для 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 для повышения производительности, но я не знаю, возможно ли это в данном конкретном случае.

...