2025, Dec 08 15:01

Внутривыборочные предсказания в skforecast без сдвига дат

Узнайте, почему сдвиг дат в skforecast не даёт in-sample оценок, и как получить корректные внутривыборочные предсказания через create_train_X_y и регрессор.

Получать внутривыборочные предсказания в skforecast непросто, если подходить к ним так же, как к прогнозу вне выборки. Возникает соблазн «проиграть прошлое», сдвинув даты и попросив алгоритм предсказать на этом искусственном горизонте. С виду идея рабочая, но истинных внутривыборочных значений подгонки она не даёт. Ниже — минимальный, воспроизводимый пример ловушки и корректный способ получить внутривыборочные предсказания, согласованные с тем, как была обучена модель.

Постановка проблемы

Пример ниже демонстрирует распространённую, но неверную стратегию: сдвигать даты экзогенных признаков так, чтобы исторические данные считались будущими, и затем вызывать predict. Код выполняется, но на выходе — не внутривыборочные оценки подгонки.

import pandas as pd
from skforecast.ForecasterAutoreg import ForecasterAutoreg
from sklearn.linear_model import LinearRegression

# Пример данных
target = pd.Series([1, 2, 3, 4, 5], index=pd.date_range("2023-01-01", periods=5, freq="D"))
aux = pd.DataFrame({"var": [10, 20, 30, 40, 50]}, index=target.index)

# Обучаем прогнозировщик
predictor = ForecasterAutoreg(regressor=LinearRegression(), lags=2)
predictor.fit(y=target, exog=aux)

# Попытка получить внутривыборочные предсказания сдвигом дат экзогенных признаков
def make_insample_guess(model, exog_frame, freq="D"):
    step_count = exog_frame.shape[0]
    last_seen = model.last_window_.index.max()
    one_step = pd.offsets.Day(1)
    exog_future = exog_frame.copy()
    exog_future.index = pd.date_range(start=last_seen + one_step, periods=step_count, freq=freq)
    return model.predict(steps=step_count, exog=exog_future).set_axis(exog_frame.index)

# Значения получаются, но это не истинные внутривыборочные оценки подгонки
guess = make_insample_guess(predictor, aux)
print(guess)

Что на самом деле идёт не так

Этот подход не создаёт внутривыборочные предсказания. Он запускает обычный рекурсивный многошаговый прогноз от конца обучающего набора, подмешивая при этом несинхронизированные экзогенные значения, которые на самом деле относились к прошлому. Внутривыборочные предсказания, напротив, должны опираться на ту же структуру лагов и те же экзогенные переменные, что и при обучении, выдавая одношаговые оценки подгонки для всех индексов, которые предсказуемы с учётом максимального лага.

Иными словами, просто сдвигая даты и прогнозируя вперёд, вы создаёте новый, синтетический сценарий вне выборки. Это не восстанавливает того, как модель предсказывала бы каждую точку во время обучения при корректных признаках, построенных из исторических лагов и исходных экзогенных данных.

Правильный подход

Чтобы получить внутривыборочные предсказания, воспользуйтесь построением признаков самим прогнозировщиком на обучающем ряду и экзогенных данных, а затем прогоните по этим признакам уже обученный регрессор. В результате вы получите оценки подгонки, выровненные по исходным предсказуемым индексам.

import pandas as pd
from skforecast.ForecasterAutoreg import ForecasterAutoreg
from sklearn.linear_model import LinearRegression

# Пример данных
ts = pd.Series([1, 2, 3, 4, 5], index=pd.date_range("2023-01-01", periods=5, freq="D"))
exo = pd.DataFrame({"var": [10, 20, 30, 40, 50]}, index=ts.index)

# Обучаем прогнозировщик
autoreg = ForecasterAutoreg(regressor=LinearRegression(), lags=2)
autoreg.fit(y=ts, exog=exo)

# Корректные внутривыборочные предсказания на обучающей матрице признаков
def fitted_insample(model, y_series, exog_frame=None):
    X_mat, y_obs = model.create_train_X_y(y=y_series, exog=exog_frame)
    y_hat = model.regressor.predict(X_mat)
    return pd.Series(y_hat, index=y_obs.index, name="in_sample_pred")

insample = fitted_insample(autoreg, y_series=ts, exog_frame=exo)
print(insample)

Почему это важно

Внутривыборочные предсказания решают иную задачу, чем прогнозирование будущего. Они позволяют оценить, насколько хорошо подогнанная модель воспроизводит обучающие данные при точно тех же лаговых признаках и экзогенных входах, что использовались при обучении. Это критично для диагностики, анализа остатков и базовых проверок. Если же рассматривать историю как «будущее» путём сдвига дат, граница размывается, и проблемы с согласованием признаков или качеством подгонки могут остаться незамеченными.

Итог

Нужны внутривыборочные предсказания — соберите матрицу признаков из исходного обучающего окна и экзогенных данных и примените к ней регрессор. Нужны прогнозы вне выборки — запрашивайте у прогнозировщика шаги вперёд от последнего обучающего индекса, передавая корректно выровненные будущие экзогенные значения. Чёткое разделение этих двух маршрутов помогает корректно оценивать подгонку и уверенно строить прогнозы.