Как определить оптимальное значение для разбиения данных (train/test/val split)?

«Как определить оптимальное значение для разбиения данных (train/test/val split)?» — вопрос из категории Предобработка данных, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Я выбираю стратегию разбиения, исходя из размера данных, стабильности оценки и типа задачи.

Мои практические правила:

Размер датасета Типовая схема Обоснование и пример
Очень маленький (< 1k samples) 60/20/20 или даже 70/15/15 Максимизирую обучающую выборку, использую кросс-валидацию для валидации.
Средний (1k - 100k samples) 70/15/15 или 80/10/10 Стандартный баланс между обучением и надёжной оценкой.
Крупный (> 100k samples) 98/1/1 или 99/0.5/0.5 Даже 1% от большого датасета даёт точную оценку, основная часть идёт в обучение.

Код для стандартного случая:

from sklearn.model_selection import train_test_split

# Первое разбиение: на тренировочный и временный (test + val) наборы
X_train, X_temp, y_train, y_temp = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)
# Второе разбиение: отделяем валидацию от теста
X_val, X_test, y_val, y_test = train_test_split(
    X_temp, y_temp, test_size=0.5, random_state=42, stratify=y_temp
)
# Итог: 70/15/15
print(f"Train: {X_train.shape[0]}, Val: {X_val.shape[0]}, Test: {X_test.shape[0]}")

Критические нюансы, которые я проверяю:

  1. Стратификация. Для классификации всегда использую stratify=y, чтобы распределение целевого класса сохранялось во всех подвыборках.
  2. Временные ряды. Здесь разбиение должно быть хронологическим. Я использовал TimeSeriesSplit из sklearn или просто задавал граничную дату: всё, что до неё — train, после — test.
  3. Стабильность оценки. Я делаю несколько случайных разбиений (с разными random_state) и смотрю, сильно ли колеблется метрика на тесте. Если колебания велики (например, AUC меняется на ±0.03), значит, тестовая выборка слишком мала или данные неоднородны — нужно увеличить её размер.