Как увеличить влияние объясняющей переменной на Y, когда мы шагнем вперед во времени?

1

Вопрос:

Я строю модель на трех временных рядах, где Y - зависимая переменная, а X1 и X2 - объясняющие переменные. Скажем, что есть веские основания полагать, что влияние X1 на Y возрастает по сравнению с X2 с течением времени. Как вы можете объяснить это в модели с несколькими регрессиями? (Я покажу фрагменты кода по мере продвижения моего вопроса, и в конце вы найдете полный раздел кода.)

Детали - визуальный подход:

Вот три синтетические серии, где кажется, что влияние X1 на Y очень сильно в конце периода:

Изображение 174551

Базовой моделью может быть:

model = smf.ols(formula='Y ~ X1 + X2')

И если вы построите установленные значения против наблюдаемых значений Y, вы получите следующее:

Изображение 174551

И, придерживаясь визуальной оценки модели, кажется, что она работает нормально в течение большей части периода, но очень плохо после того, как вступает в силу. Как я могу объяснить это в модели с множественной регрессией? С помощью этого поста я попытался ввести термин взаимодействия с линейной и квадратичной меткой времени в этих моделях:

mod_timestep  = Y ~ X1 + X2:timestep
mod_timestep2 = Y ~ X1 + X2:timestep2

Кстати, это временные метки:

Изображение 174551

Изображение 174551

Результаты:

Изображение 174551

Кажется, что оба подхода в конце концов немного улучшились, но в начале значительно хуже.

Любые другие предложения? Я знаю, что существует множество возможностей с отстающими терминами зависимой модели и другими моделями, такими как ARIMA или GARCH. Но по ряду причин я хотел бы оставаться в границах нескольких линейных регрессий и, если возможно, не отставать.

Здесь все для простой копии и вставки:

#%%
# imports
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.dates as mdates
import numpy as np
import statsmodels.api as sm
import statsmodels.formula.api as smf
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)

###############################################################################
# Synthetic Data and plot
###############################################################################

# Function to build synthetic data
def sample():

    np.random.seed(26)
    date = pd.to_datetime("1st of Dec, 1999")

    nPeriod = 250

    dates = date+pd.to_timedelta(np.arange(nPeriod), 'D')
    #ppt = np.random.rand(1900)
    Y = np.random.normal(loc=0.0, scale=1.0, size=nPeriod).cumsum()
    X1 = np.random.normal(loc=0.0, scale=1.0, size=nPeriod).cumsum()
    X2 = np.random.normal(loc=0.0, scale=1.0, size=nPeriod).cumsum()

    df = pd.DataFrame({'Y':Y,
                       'X1':X1,
                       'X2':X2},index=dates)
    # Adjust level of series
    df = df+100

    # A subset
    df = df.tail(50)
    return(df)

# Function to make a couple of plots
def plot1(df, names, colors):

    # PLot
    fig, ax = plt.subplots(1)
    ax.set_facecolor('white')

    # Plot series
    counter = 0

    for name in names:
        print(name)
        ax.plot(df.index,df[name], lw=0.5, color = colors[counter])
        counter = counter + 1

    fig = ax.get_figure()

    # Assign months to X axis
    locator = mdates.MonthLocator()  # every month

    # Specify the X format
    fmt = mdates.DateFormatter('%b')
    X = plt.gca().xaxis
    X.set_major_locator(locator)
    X.set_major_formatter(fmt)
    ax.legend(loc = 'upper left', fontsize ='x-small')
    fig.show()

# Build sample data
df = sample()

# PLot of input variables
plot1(df = df, names = ['Y', 'X1', 'X2'], colors = ['red', 'blue', 'green'])

###############################################################################
# Models
###############################################################################

# Add timesteps to original df
timestep = pd.Series(np.arange(1, len(df)+1), index = df.index)
timestep2 = timestep**2
newcols2 = list(df)
df = pd.concat([df, timestep, timestep2], axis = 1)

newcols2.extend(['timestep', 'timestep2'])
df.columns = newcols2

def add_models_to_df(df, models, modelNames):

    df_temp = df.copy()

    counter = 0
    for model in models:
        df_temp[modelNames[counter]] = smf.ols(formula=model, data=df).fit().fittedvalues
        counter = counter + 1

    return(df_temp)

df_models = add_models_to_df(df, models = ['Y ~ X1 + X2', 'Y ~ X1 + X2:timestep', 'Y ~ X1 + X2:timestep2'],
                             modelNames = ['mod_regular', 'mod_timestep', 'mod_timestep2'])


# Models
df_models = add_models_to_df(df, models = ['Y ~ X1 + X2', 'Y ~ X1 + X2:timestep', 'Y ~ X1 + X2:timestep2'],
                             modelNames = ['mod_regular', 'mod_timestep', 'mod_timestep2'])

# Plots of models
plot1(df = df_models,
      names = ['Y', 'mod_regular', 'mod_timestep', 'mod_timestep2'],
      colors = ['red', 'black', 'green', 'grey'])

Изменить 1 - снимок экрана с предложения: **

Изображение 174551

  • 1
    Я сделал трехмерную диаграмму рассеяния X1, X2 и Y. После поворота вида в трехмерном пространстве данные выглядят как «облако точек» без визуально очевидных отношений, которые можно смоделировать как «Y = f (X1, X2»). ) "- что имеет смысл в том, как sample () кодируется с использованием np, random. Может быть полезно выполнить это упражнение с исходными данными, чтобы увидеть, очевидны ли какие-либо очевидные трехмерные отношения.
  • 0
    Так что, если я правильно понимаю, вы хотите иметь больший вес (важность) для последних наблюдений (X1)?
Показать ещё 3 комментария
Теги:
regression
statsmodels

1 ответ

1
Лучший ответ

Использование других опций в приведенной вами ссылке будет лучшим вариантом.

Используя ваши функции с Y ~ X1 + X2*timestep и Y ~ X1 + X2*timestep2, по крайней мере "поймает" увеличение Y в начале, уменьшение середины периода и внезапное увеличение конца.

Я не могу опубликовать изображения, поэтому вам придется попробовать себя.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню