Как провести кросс-валидацию на временных рядах
Что проверяют
Понимаете ли вы, почему обычный KFold с перемешиванием на временном ряде завышает качество, и умеете ли построить разбиение, похожее на реальную эксплуатацию модели. Следом спрашивают про утечки через признаки и про зазор между обучением и тестом.
Как отвечать
Принцип один: модель учится только на прошлом и проверяется на будущем, как в проде. Дальше варианты:
- расширяющееся окно:
TimeSeriesSplitиз scikit-learn, по умолчаниюn_splits=5. Каждый фолд обучается на всём, что было до теста, тест сдвигается вперёд; - скользящее окно: тот же
TimeSeriesSplitсmax_train_size. Нужно, когда старые данные устарели по смыслу, например после смены цен; - размер теста:
test_sizeставят равным горизонту прогноза. Прогнозируете на 7 дней, проверяйте на 7 днях; - зазор: параметр
gapвыбрасывает точки между трейном и тестом. Он нужен, если признаки строятся на окнах или прогноз делается с задержкой, иначе соседние дни протекают в признаки; - несколько рядов: для панели магазинов или товаров режьте по общей временной границе, а не по строкам.
Утечки чаще прячутся не в разбиении, а в подготовке. Скейлер или target encoding, обученные на всём датасете, видят будущее: оборачивайте их в Pipeline, чтобы они обучались внутри фолда. Лаги и скользящие средние считайте со сдвигом (shift(1) перед rolling).
Метрики по задаче: MAE и RMSE; MAPE ломается на нулях; MASE сравнивает модель с наивным прогнозом. Покажите и сам наивный бейзлайн: «как вчера» или «как неделю назад» бывает неожиданно сильным. Гиперпараметры подбирайте тем же разбиением (GridSearchCV(cv=TimeSeriesSplit(...))), финальную оценку делайте на отложенном последнем отрезке.
Где спотыкаются
Берут train_test_split, у которого shuffle=True по умолчанию. Метрика отличная, в проде модель проваливается.
Называют скользящим окном то, что на самом деле расширяющееся, и не могут объяснить, когда какое выбрать.
Считают признаки на всём ряде до разбиения. Разбиение правильное, а скользящее среднее уже содержит значения из теста.