Как разбивать выборку, чтобы избежать дисбаланса таргета?
Что проверяют
Различаете ли вы две задачи: сохранить пропорции классов при разбиении и научить модель работать с редким классом. Интервьюер ждёт, что балансировка не попадёт в тест. Следом спрашивают, какую метрику вы возьмёте, если положительных примеров 1%.
Как отвечать
Начните с честной оговорки: разбиение дисбаланс не устраняет. Оно только гарантирует, что в каждой части редкий класс представлен в той же доле, что и в исходных данных.
- стратификация:
train_test_split(X, y, stratify=y), в кросс-валидацииStratifiedKFold. Если строки группируются по пользователю, нуженStratifiedGroupKFold, иначе один клиент окажется и в train, и в тесте; - мало примеров: при паре сотен положительных метрика на одном тесте сильно шумит, поэтому берут
RepeatedStratifiedKFoldи смотрят разброс; - регрессия: непрерывный таргет разбивают на квантильные корзины и стратифицируют по ним;
- балансировка только в train: oversampling, undersampling и SMOTE применяют после разбиения и внутри каждого фолда. Удобно через
Pipelineиз imbalanced-learn: он делает ресэмплинг только при обучении; - без ресэмплинга: часто хватает весов,
class_weight="balanced"в scikit-learn илиscale_pos_weightв XGBoost и LightGBM, плюс подбор порога на валидации.
Тест оставляют с естественным распределением: в проде модель увидит именно его. Метрики: PR-AUC, recall при заданной precision, F1 по редкому классу, матрица ошибок. ROC-AUC при сильном дисбалансе выглядит оптимистично, потому что доля ложных срабатываний считается от огромного числа негативов.
Где спотыкаются
Делают SMOTE или дублирование до разбиения. Синтетические точки и копии попадают в тест рядом со своими оригиналами, и оценка завышается.
Балансируют тестовую выборку «для честности». Метрики на ней не отражают реальное соотношение классов, и precision в проде окажется заметно ниже.
Меряют accuracy. При соотношении 99 к 1 константный ответ даёт 99%, и без PR-AUC или recall проблему не видно.