машинное обучение
January 6, 2023

Группировка по выборкам для временных рядов в sklearn

Единственная сила, способная умерять индивидуальный эгоизм, — это сила группы (Эмиль Дюркгейм). Создание выборок для временных рядов имеет свои особенности, связанные с тем, что в реальности предсказания по времени происходят позже обучения. Этот принцип надо соблюдать и при валидации моделей. Создадим демонстрационный набор данных:

import pandas as pd

df = pd.DataFrame({'val':[23, 44, 21, 221, 2, 21, 22, 123, 32], 
                   'month':pd.period_range(start='2022-01', end='2022-09', freq='M'),
                   },
                  index = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']) 
df['target'] = df['val']**2
df.head(2)

Простым способом создания выборок является отсечение по времени либо использование train_test_split. При этом следует помнить, что перед этим ряд следует упорядочить по времени и параметр shuffle установить в False:

from sklearn.model_selection import train_test_split

X_tr, X_ts = train_test_split(df, test_size=0.2, shuffle=False)
X_tr

Еще в scikit-learn есть класс TimeSeriesSplit для проведения кросс-валидации. Он проходит n_splits раз по данным с расширяющимся окном так, чтобы в тестовую выборку попадали более поздние точки. Каждая новая тренировочная выборка является расширением старой с добавлением новых точек, а размер тестовой не меняется просто захватываются более "свежие" точки. По умолчанию размер тренировочной выборки на cплите i (всего n_splits): i * n_samples // (n_splits + 1) + n_samples % (n_splits + 1), а тестовой: n_samples//(n_splits + 1):

from sklearn.model_selection import TimeSeriesSplit
sp = TimeSeriesSplit(n_splits=3)

for tr_idx, val_idx in sp.split(df):
  display(tr_idx)
  display(val_idx)
  print('------------')

Также можно увеличить разрыв между тренировочной и тестовой выборкой, используя параметр gap (убирает из тренировочной выборки gap последних наблюдений):

sp = TimeSeriesSplit(n_splits=3, gap=2)

for tr_idx, val_idx in sp.split(df):
  display(tr_idx)
  display(val_idx)
  print('------------')