StratifiedKFold и редкий класс: что делать, если объектов меньше, чем фолдов
В наборе всего три подтверждённых мошеннических заявки. Команда ставит привычные пять фолдов и хочет посчитать средний ROC AUC. Проблема видна ещё до модели: пять тестовых частей не могут получить хотя бы по одному положительному случаю, если таких случаев всего три. На некоторых фолдах ROC AUC вообще не определён. Стратификация старается сохранить доли классов, но не создаёт отсутствующие объекты.
Сначала посчитайте самый маленький класс
StratifiedKFold распределяет объекты каждого класса между фолдами настолько равномерно, насколько позволяют целые числа. Если положительных случаев три, три фолда дадут по одному в каждом тесте. Это нижняя граница содержательной оценки, а не знак стабильности: метрика по одному событию будет сильно прыгать. Число фолдов выбирают с учётом не только общего размера таблицы, но и минимального класса.
Ниже короткая проверка состава фолдов. Мы не обучаем модель, потому что ошибка возникает на этапе разбиения. Код печатает число положительных объектов в train и test; проверка требует один случай в каждом test.
import numpy as np
from sklearn.model_selection import StratifiedKFold
y = np.array([0] * 12 + [1] * 3)
X = np.arange(len(y)).reshape(-1, 1)
cv = StratifiedKFold(n_splits=3, shuffle=True, random_state=4)
for fold, (train, test) in enumerate(cv.split(X, y), 1):
print(fold, "train positives", int(y[train].sum()),
"test positives", int(y[test].sum()))
assert y[test].sum() == 1
print("минимальный размер класса:", int(np.bincount(y).min()))В каждом тестовом фолде оказывается одна положительная заявка, в обучении — две. Теперь метрику технически можно вычислить, но уверенности она даёт мало: порядок одного объекта способен заметно поменять результат. Запишите рядом с оценкой поддержку класса и разброс по фолдам. Если результат нужен для решения о запуске, лучше накопить больше подтверждённых случаев или использовать более длинный период наблюдения.
Почему уменьшить n_splits бывает правильнее
Слишком большое число фолдов даёт тестовые части без редкого класса и ломает расчёт метрик, которым нужны оба класса. Слишком маленькое оставляет мало независимых проверок. При очень редком событии ни один выбор n_splits не компенсирует недостаток данных. Можно оценивать метрики по совокупности out-of-fold прогнозов, но и там число положительных случаев остаётся прежним. Интервал неопределённости и ошибка на новых периодах важнее красивого среднего балла.
Ещё один выбор касается независимости строк. Если несколько заявок относятся к одному клиенту, обычный StratifiedKFold может поместить его записи в обе части. Тогда модель узнает клиента вместо общего паттерна. Используйте групповой подход, когда прогноз должен работать на новых клиентах; пример такой утечки есть в статье про GroupKFold. Если мошенничество меняется по месяцам, временная проверка может лучше соответствовать эксплуатации, даже если доли классов в периодах неравны.
Когда редкий класс уже достаточно представлен, выберите метрику под действие. ROC AUC требует обоих классов, а для очереди ручных проверок полезны average precision и число найденных случаев на доступное число проверок. Разбор PR-кривой для редкого класса показывает, как учитывать базовую долю события. Сначала добейтесь честного разбиения, затем сравнивайте модели.
Стратификация не должна менять то, как выглядит будущий поток. Если мошенничество в апреле стало заметно чаще, одинаковые доли во всех случайных фолдах сгладят сдвиг, который модель встретит после запуска. Тогда лучше взять несколько последовательных периодов и сообщить, сколько положительных случаев было в каждом, даже если оценка получается неудобной. Для повторных клиентов требования ко времени и группам приходится согласовывать с размером редкого класса; иногда данных пока недостаточно для обещанного уровня уверенности.
В курсе «ML Engineer / Data Scientist: табличные модели в продакшн» вы работаете с валидацией, метриками и типичными провалами качества, после чего собираете воспроизводимый пайплайн. Это помогает включить проверку состава фолдов в стандартный эксперимент, а не обнаруживать пустой класс после запуска тюнинга. Посмотрите программу курса.
Продолжить на практике
- ML Engineer / Data Scientist: табличные модели в продакшн ↗
Практический курс для тех, кто хочет получить навыки ML Engineer / Data Scientist на реальных табличных задачах. В курсе Вы не просто обучите CatBoost/LightGBM, а соберёте полноценный production-style пайплайн: подготовка данных, feature engineering (генерация признаков), корректная валидация, защита от leakage (утечек), тюнинг через Optuna, интерпретация через SHAP, batch-инференс и REST API для предсказаний.
