ROC AUC высокий, а вероятности обманывают: проверяем калибровку модели
Модель ранжирует заявки на отказ от подписки. Команда берёт пользователей с вероятностью выше 0,8 и планирует для них дорогой звонок. На тесте ROC AUC выглядит хорошо, но среди людей с прогнозом около 0,9 отказывается заметно меньше девяти из десяти. Модель помогает выбрать очередность звонков, однако её число нельзя напрямую использовать как оценку ожидаемых затрат.
Здесь расходятся два вопроса. Дискриминация отвечает, поставит ли модель будущего отказника выше человека, который останется. Калибровка отвечает, совпадает ли доля реальных отказов с выданной вероятностью в группах похожих прогнозов. Первая важна для очереди, вторая — для расчёта стоимости действия и выбора порога по экономике.
Один и тот же порядок, разные вероятности
Представим восемь наблюдений, разделённых моделью на две равные группы. В нижней группе реально отказывается один человек из четырёх, в верхней — трое из четырёх. Исходная модель выдаёт всем нижним 0,1, верхним 0,9. После перенастройки числа становятся 0,25 и 0,75. Порядок людей не поменялся; честность вероятностей изменилась.
import numpy as np
from sklearn.calibration import calibration_curve
from sklearn.metrics import brier_score_loss, roc_auc_score
y = np.array([0, 0, 0, 1, 0, 1, 1, 1])
raw = np.array([.1] * 4 + [.9] * 4)
adjusted = np.array([.25] * 4 + [.75] * 4)
for name, p in [("исходные", raw), ("скорректированные", adjusted)]:
observed, predicted = calibration_curve(y, p, n_bins=2, strategy="uniform")
print(name, "AUC", round(roc_auc_score(y, p), 4),
"Brier", round(brier_score_loss(y, p), 4))
print("доли", observed.tolist(), "прогнозы", predicted.tolist())Для обоих наборов AUC = 0,75. У исходных вероятностей Brier = 0,21, у скорректированных — 0,1875. Код также печатает фактические доли [0.25, 0.75]. Им соответствуют средние исходные прогнозы [0.1, 0.9] и скорректированные [0.25, 0.75]. Вторая пара на этом игрушечном наборе лежит на диагонали калибровки.
Brier score — средний квадрат разницы между вероятностью положительного класса и фактом 0/1; меньше — лучше. Однако один Brier не изолирует калибровку: в нём отражается и способность различать классы. Поэтому рядом смотрят ROC AUC, таблицу долей по диапазонам прогнозов и количество наблюдений в каждом диапазоне. На восьми объектах мы показываем арифметику, а решение для сервиса принимают по достаточно большому независимому набору.
Как сделать проверку на своих данных
Сначала сохраните исходные вероятности положительного класса и истинные метки на отложенном наборе. Убедитесь, что столбец predict_proba соответствует нужному классу: порядок задаётся classes_. Этому посвящён отдельный разбор порядка классов в scikit-learn. Затем разбейте прогнозы на интервалы и посчитайте в каждом число объектов, средний прогноз и долю событий. Если группа с прогнозом 0,8–0,9 стабильно даёт 0,5, расчёт звонков по ожидаемому числу отказов будет завышен.
Когда калибровка нужна в модели, отделите данные для её настройки от данных обучения классификатора и оставьте финальный тест нетронутым. В scikit-learn для этого есть CalibratedClassifierCV: он обучает преобразование исходного score в вероятность. Подбор метода и параметров проводят на валидации. Калибратор, настроенный по тем же предсказаниям, на которых классификатор обучался, обычно получает чрезмерно уверенные входы и переносится на новые данные хуже.
Есть ещё практический нюанс: границы групп по вероятности выбираются до анализа и одинаково применяются к сравниваемым моделям. Если у одной модели почти все прогнозы лежат между 0,45 и 0,55, десять равных интервалов дадут много пустых корзин. Тогда полезно группировать по квантилям и вместе с долей события показывать средний прогноз и размер группы. Маленькая группа даёт шумную оценку: один дополнительный отказ может сильно передвинуть её долю. На финальном тесте сохраняйте исходные прогнозы и правила разбиения, чтобы сравнение не зависело от красивого выбора границ задним числом.
Вернитесь к бизнес-действию после проверки. Если нужен только список первых 100 клиентов, порядок ранжирования может быть достаточен. Если вы оцениваете ожидаемую выгоду каждого звонка, в формуле нужна вероятность, соответствующая реальной частоте события. Калибровка не исправит неверный целевой признак, изменившуюся долю отказов или ошибочную цену звонка; их проверяют отдельно, потому что они меняют само решение.
Продолжение на табличных задачах
Курс «ML Engineer / Data Scientist: табличные модели в продакшн» проводит через подготовку данных, корректную валидацию, CatBoost и LightGBM, сравнение моделей и контроль качества после запуска. Вы сможете встроить проверку вероятностей в отчёт об эксперименте, а затем вынести выбранную модель в batch-инференс или REST API. Откройте программу курса и сопоставьте разделы валидации и оценки с вашей задачей.
Продолжить на практике
- ML Engineer / Data Scientist: табличные модели в продакшн ↗
Практический курс для тех, кто хочет получить навыки ML Engineer / Data Scientist на реальных табличных задачах. В курсе Вы не просто обучите CatBoost/LightGBM, а соберёте полноценный production-style пайплайн: подготовка данных, feature engineering (генерация признаков), корректная валидация, защита от leakage (утечек), тюнинг через Optuna, интерпретация через SHAP, batch-инференс и REST API для предсказаний.
