Дисбаланс классов: веса, порог и правильные метрики
При дисбалансе один класс встречается намного реже другого: дефекты, мошеннические операции или аварии могут составлять доли процента. Модель с высокой accuracy способна полностью игнорировать редкое событие, поэтому проверку начинают с матрицы ошибок и цены решений.
Сначала определите положительный класс
Редкий класс не обязательно положительный в коде. Проверьте значения y, порядок classes_ и смысл каждого исхода. Ошибка в соответствии меток меняет интерпретацию precision, recall и столбца predict_proba.
Затем посчитайте baseline: что произойдёт, если всегда прогнозировать большинство? Его accuracy показывает, насколько мало сообщает общая доля правильных ответов.
Метрики для редкого события
Recall измеряет долю найденных положительных объектов, precision — долю настоящих среди срабатываний. PR-кривая показывает их компромисс при разных порогах. F1 объединяет две величины, но предполагает одинаковую значимость и скрывает конкретное число ошибок.
ROC-AUC полезна для ранжирования, однако большое число true negatives может сделать картину менее наглядной. Показывайте также average precision или PR-AUC, матрицу ошибок и абсолютные количества на рабочем пороге.
Веса классов
Многие алгоритмы принимают class_weight='balanced' и усиливают вклад редкого класса в функцию потерь. Это меняет обучение, но не гарантирует нужного рабочего компромисса.
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import precision_recall_curve
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
X, y = make_classification(
n_samples=3_000,
n_features=12,
n_informative=6,
weights=[0.95, 0.05],
flip_y=0.01,
random_state=42,
)
X_train, X_valid, y_train, y_valid = train_test_split(
X, y, test_size=0.25, random_state=42, stratify=y
)
model = make_pipeline(
StandardScaler(),
LogisticRegression(class_weight='balanced', max_iter=2_000),
)
model.fit(X_train, y_train)
positive_label = 1
positive_index = list(model.classes_).index(positive_label)
scores = model.predict_proba(X_valid)[:, positive_index]
precision, recall, thresholds = precision_recall_curve(
y_valid, scores, pos_label=positive_label
)
# Пример требования: найти вариант с recall не ниже 0.90.
candidates = [(p, r, t) for p, r, t in zip(precision, recall, thresholds) if r >= 0.90]
best_precision, best_recall, threshold = max(candidates, key=lambda item: item[0])
print(best_precision, best_recall, threshold)Порог выбирается на validation. После выбора правило фиксируют и один раз проверяют на test вместе с абсолютным числом FP и FN.
Повторная выборка
Oversampling увеличивает представительство редкого класса, undersampling уменьшает большинство. Эти операции выполняются только внутри train-фолда. Если сначала создать копии редких объектов, а затем разделить таблицу, один исходный пример попадёт в обучение и проверку.
Синтетические методы не создают новую реальность: они интерполируют доступные наблюдения и могут усиливать шум. Сравните их с весами, изменением порога и сбором настоящих примеров.
Дисбаланс может меняться после запуска
Доля событий влияет на precision. Модель с тем же recall и false positive rate будет давать другую чистоту срабатываний, если редкий класс стал встречаться реже. Поэтому отслеживайте base rate, объём ручной проверки и качество на размеченных данных во времени.
Для очень редких событий случайный test может содержать слишком мало положительных случаев. Нужны достаточно длинное окно, интервальная оценка и предметно важные стресс-сценарии.
Практика: переведите метрики в очередь
Пусть сервис обрабатывает 100 000 заявок в день, положительный класс составляет 0,5%, recall равен 0,8, а precision — 0,2. Посчитайте найденные события, пропуски и примерный размер очереди проверок. Решите, выдерживает ли её команда, и сформулируйте ограничение для выбора порога.
Что важно запомнить
- Accuracy большинства не измеряет обнаружение редкого события.
- Порог выбирают по цене FP и FN на validation.
- Sampling выполняется только внутри обучающих фолдов.
- Отчёт должен переводить метрики в реальные количества и нагрузку.