Собесов

DataLearn ML-101: Работа с несбалансированными классами

ML / Data ScienceImbalanced learningСредняяMiddle

Условие

Антифрод: 50 млн транзакций в обучении, 0.3% — мошенничество. Какие подходы есть к работе с дисбалансом? Что не сработает / даст leakage? Дайте план эксперимента, который реально применим в проде.

Решение

Подходы

1. Class weights / sample weights

from sklearn.linear_model import LogisticRegression
LogisticRegression(class_weight='balanced')  # 1/(n_classes * np.bincount(y))

В LightGBM/XGBoost: scale_pos_weight = neg / pos. CatBoost: class_weights=[1, neg/pos].

Плюсы: ничего не делает с данными. Минусы: мало эффективно при extreme imbalance (1:1000+).

2. Undersampling большинства

Случайно выкинуть 95% «нормальных» транзакций.

from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(sampling_strategy=0.1, random_state=0)
X_res, y_res = rus.fit_resample(X, y)

Плюсы: быстрее обучение. Минусы: теряем сигнал из большинства; ROC-AUC может немного просесть.

3. Oversampling меньшинства (SMOTE)

Синтезирует новые «положительные» точки по интерполяции.

from imblearn.over_sampling import SMOTE
sm = SMOTE(sampling_strategy=0.1, k_neighbors=5, random_state=0)
X_res, y_res = sm.fit_resample(X, y)

Плюсы: больше «положительных». Минусы: на табличных табличных данных с категориальными фичами SMOTE портит распределение (категории интерполировать нельзя).

4. SMOTENC / SMOTEENN / ADASYN — варианты для категориальных и с очисткой.

5. Threshold tuning

Оставить дисбаланс как есть, обучить модель, выбрать threshold под бизнес-цель:

# fix Precision >= 0.9
p, r, thr = precision_recall_curve(y_true, y_scores)
best = (p >= 0.9) & (r > 0)
thr_best = thr[best][np.argmax(r[best])]

6. Cost-sensitive learning

Заменить cross-entropy на focal loss или асимметричную:

L = α (1 - p)^γ · log(p)

В XGBoost — кастомная loss. В Catboost — нет встроенной, можно через class_weights и auto_class_weights.

7. Anomaly detection (Isolation Forest, autoencoder) — если положительных вообще единицы.

Чего избегать

  • SMOTE до сплита train/val — leakage: синтетические точки попадут и в val.
  • Балансировка test — никогда. Метрики становятся бессмысленными.
  • Accuracy — бесполезна (предсказание «всё нормально» = 99.7%).
  • ROC-AUC как единственная метрика — может быть высоким при бесполезной модели на дисбалансе. PR-AUC честнее.

План эксперимента

  1. Baseline без балансировки: LightGBM + ROC-AUC + PR-AUC на чистом сплите (time-based).
  2. Class weights (scale_pos_weight = n_neg / n_pos) — почти бесплатное улучшение.
  3. Undersampling 1:10 — быстрее обучение, проверить, не упало ли PR-AUC.
  4. Threshold tuning под бизнес-цель (например, Precision ≥ 0.8 при максимуме Recall).
  5. Out-of-Time validation на последних 30 днях — обязательно для antifraud (дрейф паттернов).
  6. A/B на проде: новая модель vs текущая, замерять % одобрений и FN-стоимость.

Метрики для отчёта

from sklearn.metrics import (roc_auc_score, average_precision_score,
                             precision_recall_curve, fbeta_score)
 
print("ROC-AUC :", roc_auc_score(y_te, p))
print("PR-AUC  :", average_precision_score(y_te, p))
print("F2      :", fbeta_score(y_te, (p > 0.5).astype(int), beta=2))   # больше веса recall

Подводные камни

  1. SMOTE до сплита — главная ошибка. Делайте fit_resample только на train.
  2. scale_pos_weight искажает калибровку: предсказанные вероятности перестают быть «реальными». Если калибровка нужна — CalibratedClassifierCV после.
  3. Undersampling теряет сигнал: в большинстве могут быть редкие, но информативные паттерны.
  4. SMOTE для категориальных не работает — нужен SMOTENC.
  5. OOT валидация для antifraud обязательна — паттерны меняются за дни.
  6. Метрика обучения ≠ бизнес-метрика: AUC может расти, а потери — тоже (если FN дорогой).
  7. Class imbalance ≠ всегда проблема: если модель и так выделяет минорный класс — не лезьте.

Эталонный ответ

При imbalance 1:300 порядок действий:

  1. Не балансировать сразу — попробовать class weights в бустинге.
  2. Использовать PR-AUC и Precision@K, не accuracy / ROC-AUC.
  3. Out-of-Time валидация (дрейф паттернов).
  4. Threshold tuning под бизнес-цель.
  5. Балансировка train (undersampling 1:10 или SMOTENC) — только если шаги 1-4 не помогли.
  6. Никогда не балансировать test / val.
  7. Считать деньги, а не только AUC — построить profit curve.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти