Собесов

Хабр ML — работа с дисбалансом классов в классификации

ML / Data ScienceПодготовка данныхСредняяMiddle

Условие

В задаче антифрода positive класс — 0.2% наблюдений. Модель даёт accuracy 99.8%, predict_proba близко к 0. Опишите способы борьбы с дисбалансом и их компромиссы.

Решение

Почему стандартный train ломается

Loss function (cross-entropy) суммирует ошибки по всем примерам. При 0.2% positive вклад positive класса в gradient мал — модель быстро учится предсказывать почти всегда «не fraud».

Подходы

1. Изменить веса классов (class_weight). Самое простое, работает в логрег, RF, XGBoost, нейронных сетях.

from sklearn.linear_model import LogisticRegression
model = LogisticRegression(class_weight='balanced')   # или {0: 1, 1: 500}

class_weight='balanced'n / (n_classes · n_class_samples).

2. Undersampling (Random / Tomek / NearMiss). Уменьшить majority. Быстро, но теряем информацию.

from imblearn.under_sampling import RandomUnderSampler
X_res, y_res = RandomUnderSampler(random_state=42).fit_resample(X, y)

3. Oversampling (Random / SMOTE / ADASYN). Дублировать или генерировать новых positives.

from imblearn.over_sampling import SMOTE
X_res, y_res = SMOTE(random_state=42).fit_resample(X, y)

SMOTE генерирует синтетические positive интерполяцией ближайших соседей. Опасность: интерполяция бессмысленна для категориальных и для очень малых выборок positive.

4. Threshold tuning. Не менять данные, оставить модель — но сдвинуть decision threshold. У логрега или градиент бустинга порог 0.5 для дисбаланса бессмыслен — выбирайте threshold по F1, PR-AUC или business cost.

5. Anomaly detection / one-class. Для очень редких классов (< 0.1%) — Isolation Forest, One-class SVM, autoencoder reconstruction error.

6. Cost-sensitive learning. Прямо встроить разные стоимости в loss: cost_FN · y · (1-p) + cost_FP · (1-y) · p.

Сравнение подходов

Подход Плюсы Минусы
class_weight дёшево, не меняет данные не для всех алгоритмов
Undersampling быстро теряем данные, увеличиваем variance
Oversampling сохраняем данные риск overfitting на дубликатах
SMOTE синтетическое разнообразие плохо с категориями, не для маленького positive
Threshold простое, прозрачное не помогает, если модель не учится разделять
Anomaly det. для экстремального дисбаланса сложнее настроить

Правильное применение

  1. Применяйте resampling ТОЛЬКО к train, не к validation/test. Иначе оценка качества врёт.
  2. Cross-validation должна быть стратифицированной (StratifiedKFold), чтобы positive были в каждом fold.
  3. Метрика — не accuracy. PR-AUC, F1, expected cost — релевантнее.
  4. Холдаут отражает прод-распределение. Если в проде 0.2% positive — на тестовом сете тоже 0.2%.

Тонкости SMOTE

  • Generate k=5 синтетических из 5 ближайших соседей по умолчанию. Слишком высокое k → межклассовое размытие.
  • SMOTE-NC для категориальных + числовых.
  • Borderline-SMOTE генерирует только у границы классов.
  • ADASYN — больше синтетических там, где модель плохо классифицирует.

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

  1. Resampling на test → завышенная оценка качества.
  2. «Использовали SMOTE и accuracy выросла». Accuracy теряет смысл при дисбалансе.
  3. Threshold 0.5 после resampling. Имеет смысл, только если class distribution в проде совпадает с train.
  4. SMOTE на one-hot encoded категориях — мусорные центры между категориями.
  5. Игнорировать data leakage. Resampling до train/test split → утечка.
  6. «Дисбаланс = всегда проблема». Иногда модель сама прекрасно справляется (особенно градиент бустинг с правильно подобранным loss и threshold).

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

Подходы: class_weight (просто, не меняет данные), undersampling (быстро, теряем), oversampling/SMOTE (сохраняем, риск overfit), threshold tuning (часто достаточно), anomaly detection (для < 0.1%), cost-sensitive (формально). Применять только к train, оценивать на отдельной test с реальным распределением, метрика — PR-AUC / expected cost, не accuracy.

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

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

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