Почему на неравных классах модель легко кажется умной
Если в выборке 95 процентов объектов относятся к одному классу, модель может почти всегда отвечать этим классом и все равно получить высокую accuracy. Именно поэтому дисбаланс так опасен: он позволяет хорошим на вид метрикам скрывать практически бесполезное поведение модели. Для бизнес-задач это особенно критично, потому что редкий класс часто и является самым важным: мошенничество, болезнь, отказ, дефолт, инцидент.
Поэтому первая взрослая реакция на дисбаланс — перестать доверять accuracy как главному критерию.
Что именно ломается при дисбалансе
$$ Accuracy = \frac{TP + TN}{TP + TN + FP + FN} $$Accuracy складывает все правильные ответы вместе. При сильном дисбалансе большая масса true negatives может спрятать тот факт, что модель почти не находит редкий, но важный класс.
TP— верно найденные объекты редкого классаTN— верно распознанные объекты частого классаFP— ложные тревоги по редкому классуFN— пропущенные объекты редкого класса
Как только видишь эту формулу в задаче с редким классом, становится ясно, почему проблема системная. Большое количество TN может сделать accuracy высокой даже у модели, которая плохо решает главную задачу.
На что тогда смотреть
Обычно полезнее смотреть precision, recall, F1, ROC-AUC, PR-AUC и саму confusion matrix. Если особенно важно не пропустить редкий класс, ключевой становится recall. Если дорого часто ошибаться ложными тревогами, нужен precision. Иногда меняют не только метрику, но и саму стратегию обучения: class weights, resampling, threshold tuning, а иногда и саму постановку бизнес-решения.
Как это почувствовать на Python-примере
from sklearn.metrics import accuracy_score # считаем наивную общую долю правильных ответов
from sklearn.metrics import recall_score # отдельно измеряем полноту по редкому классу
from sklearn.metrics import precision_score # оцениваем чистоту положительных срабатываний
y_true = [0, 0, 0, 0, 0, 0, 0, 1] # только один объект относится к редкому классу
y_pred = [0, 0, 0, 0, 0, 0, 0, 0] # модель всегда отвечает частым классом
print('accuracy', accuracy_score(y_true, y_pred)) # видим высокую accuracy даже у плохой модели
print('recall', recall_score(y_true, y_pred, zero_division=0)) # обнаруживаем, что редкий класс вообще не найден
print('precision', precision_score(y_true, y_pred, zero_division=0)) # положительных срабатываний нет совсемТакой короткий пример очень отрезвляет. Он показывает, что дисбаланс — это не частный corner case, а полноценная задача выбора правильной метрики и стратегии обучения.