🏢 Ситуация
Вас переводят в антифрод-подпроект. Игорь вводит в курс:
«Кошелёк Datacore процессит 400 000 транзакций в день. Фрод — 0.1%, но каждый пропущенный кейс — в среднем −18 000 ₽, а каждая ложная блокировка честного клиента — звонок в поддержку (−400 ₽) и злой клиент. Команда ручной проверки разбирает максимум 500 алертов в день. Твоя модель должна жить в этих ограничениях. Дисбаланс 1:1000 — здесь ломаются все привычки из учебников.»
🎯 Ваша задача
- Понять, что ломается при сильном дисбалансе и как это чинить.
- Освоить class weights, oversampling/undersampling, SMOTE — и их ограничения.
- Выбрать порог из экономики и операционных лимитов.
📚 Теория
Что ломается при дисбалансе 1:1000
- Accuracy бессмысленна (модуль 6): константа «не фрод» даёт 99.9%.
- Функция потерь почти не видит редкий класс: 0.1% примеров дают 0.1% градиента — модель учится игнорировать фрод.
- ROC-AUC обманчиво высок; смотрите PR-AUC и precision/recall в рабочей точке.
Способы борьбы
| Метод | Суть | Плюсы / минусы |
|---|---|---|
Class weights (class_weight="balanced", scale_pos_weight) |
ошибки на редком классе штрафуются сильнее | просто, без искажения данных; первый выбор |
| Undersampling | выбросить часть мажоритарного класса | быстрее обучение; теряем информацию |
| Oversampling | дублировать редкий класс | риск переобучения на дубликаты |
| SMOTE | синтетические примеры между соседями редкого класса | помогает слабым моделям; для бустинга часто бесполезен, создаёт нереалистичные точки |
| Подбор порога | не трогать данные, сдвинуть решение | обязателен всегда, что бы вы ни делали выше |
Практика индустрии: для бустинга — веса классов + подбор порога. Сэмплирование — когда данные не влезают или модель совсем слаба.
⚠️ Золотые правила:
- Сэмплирование применяем только к train, никогда к валидации/тесту — иначе метрики измерены на «фантазийном» мире.
- После ресэмплинга/весов предсказанные вероятности смещены — их нельзя читать как реальные частоты без калибровки (
CalibratedClassifierCV).
Порог из экономики
Ожидаемая ценность алерта при пороге t:
V(t) = TP(t)·18000 − FP(t)·400, при ограничении TP(t)+FP(t) ≤ 500/день.
Порог — это решение задачи оптимизации, а не константа 0.5.