Ответ
Я выбираю стратегию разбиения, исходя из размера данных, стабильности оценки и типа задачи.
Мои практические правила:
| Размер датасета | Типовая схема | Обоснование и пример |
|---|---|---|
| Очень маленький (< 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]}")
Критические нюансы, которые я проверяю:
- Стратификация. Для классификации всегда использую
stratify=y, чтобы распределение целевого класса сохранялось во всех подвыборках. - Временные ряды. Здесь разбиение должно быть хронологическим. Я использовал
TimeSeriesSplitиз sklearn или просто задавал граничную дату: всё, что до неё — train, после — test. - Стабильность оценки. Я делаю несколько случайных разбиений (с разными
random_state) и смотрю, сильно ли колеблется метрика на тесте. Если колебания велики (например,AUCменяется на ±0.03), значит, тестовая выборка слишком мала или данные неоднородны — нужно увеличить её размер.
Ответ 18+ 🔞
Давай разберём эту тему, а то у некоторых тут стратегия как у мартышлюшки с гранатой — куда кинет, не угадаешь. Я выбираю, как делить данные, глядя на три вещи: сколько их вообще, насколько стабильно модель оценивается и что за задача перед нами стоит.
Вот мои правила, по которым я обычно работаю:
| Размер датасета | Как обычно делю | Почему именно так и пример |
|---|---|---|
| Очень маленький (< 1k примеров) | 60/20/20 или даже 70/15/15 | Тут надо выжать из обучающей выборки всё, что можно. Валидацию часто делаю через кросс-валидацию, чтобы не оставить модель голодной. |
| Средний (1k - 100k примеров) | 70/15/15 или 80/10/10 | Золотая середина. Обучаться есть на чём, и на валидации с тестом уже можно что-то понять, а не гадать на кофейной гуще. |
| Очень крупный (> 100k примеров) | 98/1/1 или 99/0.5/0.5 | Когда данных овердохуища, даже один процент — это уже толковая выборка для оценки. Зачем отдавать лишнее, если модель и так нажрётся? |
Вот код для самого частого, среднего случая:
from sklearn.model_selection import train_test_split
# Сначала откусываем кусок на тест и валидацию вместе
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]}")
А теперь главное, на что я смотрю, чтобы не облажаться:
- Стратификация. Если задача классификация, я всегда ставлю
stratify=y. Иначе может получиться, что в трейне одни классы, а в тесте — другие. Это пиздец, а не оценка. - Временные ряды. Тут, ёпта, никаких случайных разбиений! Всё должно идти по порядку. Я использовал
TimeSeriesSplitили просто брал всё до определённой даты для обучения, а что после — для теста. Иначе ты обманешь модель будущими данными, и она себя покажет как гений, а на деле — хуй с горы. - Стабильность оценки. Я делаю несколько разбиений с разными
random_stateи смотрю, как прыгает метрика на тесте. Если она скачет, как угорелая (допустим,AUCпляшет на ±0.03), это тревожный звоночек. Значит, или теста маловато, или данные — хитрая жопа. Надо увеличивать тестовую выборку.