- BrainTools - https://www.braintools.ru -
Самая распространённая ошибка [1] при работе с вероятностями в ML — читать число из predict_proba как вероятность. Модель вернула 0.9, и кажется очевидным: «событие произойдёт примерно в 90 случаях из 100». На этом строят решения — ранжируют лиды по этому числу, ставят порог отсечения, считают ожидаемую выручку как 0.9 * сумма_сделки, показывают пользователю «уверенность 90%».
А потом расчёты ожидаемой выручки систематически расходятся с фактом, сравнение «0.7 против 0.9» означает совсем не то, что предполагалось, а порог отсечения стоит не там, где надо. При этом AUC модели прекрасный, и кажется, что с моделью всё в порядке.
predict_proba возвращает не вероятность, а оценку, внутреннюю уверенность модели, втиснутую в диапазон от нуля до единицы. Синтаксически это похоже на вероятность: число в [0, 1], по классам сумма равна единице. Но означает ли «0.9», что среди подобных объектов положительных действительно около 90%, — это отдельное свойство, оно называется калибровкой, и по умолчанию большинство моделей им не обладает.
В статье рассмотрим, чем калибровка отличается от ранжирующей способности, почему разные модели выдают смещённые вероятности, каждая по-своему и как увидеть смещение на графике надёжности, как его починить и в каких задачах это вообще важно.
Вероятность откалибрована, если выполняется частотная интерпретация: среди всех объектов, которым модель присвоила оценку около 0.8, положительных действительно примерно 80%. Это определение и есть смысл слова «вероятность» применительно к выходу модели.
predict_proba всегда даёт число в [0, 1]. Откалибровано ли оно — вопрос отдельный, и ответ на него ничем не гарантирован.
Здесь полезно развести два независимых качества классификатора. Первое — ранжирующая способность: умеет ли модель ставить положительные объекты выше отрицательных. Её измеряет AUC. Второе — калибровка: совпадают ли сами числа с наблюдаемыми частотами.
Эти качества независимы друг от друга, и AUC не видит калибровку в принципе. AUC — это вероятность того, что случайный положительный объект получит оценку выше случайного отрицательного, то есть величина чисто порядковая. Возьмите все предсказанные вероятности и возведите их в квадрат — порядок объектов не изменится, AUC останется прежним, а калибровка будет разрушена. Модель с AUC 0.95 может быть откалибрована сколь угодно плохо. Хороший AUC не говорит ровным счётом ничего о том, означает ли «0.9» девяносто процентов.
Смещение predict_proba — не случайность [2] и не баг конкретной библиотеки. Оно вытекает из того, как устроена модель. Разберём по семействам.
Логистическая регрессия обучается минимизацией log-loss — функции, которая достигает минимума ровно тогда, когда предсказанные числа совпадают с истинными вероятностями. Поэтому логистическая регрессия обычно откалибрована неплохо: давать честные вероятности буквально цель её обучения [3].
Случайный лес устроен иначе и ведёт себя противоположно. Его predict_proba — это усреднённая по всем деревьям оценка класса. Чтобы лес выдал 1.0, к этому значению должно прийти каждое дерево. Но деревья обучены на бутстрэп-выборках со случайными подмножествами признаков, поэтому на почти любом объекте хотя бы одно дерево даст оценку, далёкую от единицы. Среднее оттягивается от 0 и от 1 к середине. Случайный лес недоуверен: когда он выдаёт 0.9, истинная доля положительных обычно выше, а гистограмма его вероятностей упирается в пики около 0.2 и 0.9, и почти ничего нет у краёв.
Наивный Байес смещён в другую сторону. Он предполагает, что признаки независимы. Когда признаки на самом деле скоррелированы, он учитывает одно и то же свидетельство несколько раз — «считает дважды», — и произведение схлопывается к 0 или 1. Наивный Байес переуверен: говорит 0.99 там, где в реальности 0.85.
Метод опорных векторов вероятностей не выдаёт в принципе. Опция probability=True достраивает поверх решающей функции отдельную сигмоиду — это аппроксимация, и для методов максимального зазора она обычно даёт недоуверенные оценки.
Вывод из этого один. Число из
predict_proba— побочный продукт того, как модель оптимизировалась, а не измеренная частота. Откалиброванную вероятность выдают лишь некоторые модели и лишь при некоторых условиях.predict_probaотдаёт вам внутреннюю оценку модели, нормированную в[0, 1]; называть её вероятностью — это ваше допущение, а не обещание модели.
Калибровку не нужно угадывать — её видно. Инструмент называется графиком надёжности (reliability diagram), и строится он так: предсказания разбивают на корзины по значению, и для каждой корзины считают две величины — среднюю предсказанную вероятность и фактическую долю положительных объектов.
from sklearn.calibration import calibration_curve
prob_true, prob_pred = calibration_curve(y_test, y_proba, n_bins=10)
Если отложить prob_pred по горизонтали, а prob_true по вертикали, у идеально откалиброванной модели точки лягут на диагональ: предсказал 0.8 — получил 80% положительных. У случайного леса кривая пойдёт S-образно, провисая ниже диагонали на низких оценках и поднимаясь выше на высоких, — картина недоуверенности. У наивного Байеса перекос будет обратным.
Есть и числовая мера, не требующая графика, — Brier score, средний квадрат отклонения предсказанной вероятности от фактического исхода 0 или 1:
from sklearn.metrics import brier_score_loss
score = brier_score_loss(y_test, y_proba)
В отличие от AUC, Brier score штрафует именно за нечестные числа. Разумная практика — смотреть обе метрики: AUC отвечает за порядок, Brier score (или log-loss) — за то, можно ли верить самим вероятностям.
Калибровка — это отдельный шаг после обучения модели. Поверх обученной модели ставится преобразование, которое переводит её сырые оценки в честные вероятности, и обучается это преобразование на отложенных данных. В sklearn за это отвечает CalibratedClassifierCV:
from sklearn.calibration import CalibratedClassifierCV
from sklearn.ensemble import RandomForestClassifier
calibrated = CalibratedClassifierCV(
RandomForestClassifier(), method='isotonic', cv=5
)
calibrated.fit(X_train, y_train)
proba = calibrated.predict_proba(X_test)[:, 1]
Метода два. method='sigmoid' — это шкалирование Платта: поверх оценок подгоняется сигмоида. Параметров у неё мало, она устойчива на небольших выборках, но предполагает, что искажение имеет именно сигмоидную форму. method='isotonic' — изотоническая регрессия: непараметрическое монотонное преобразование, оно гибче и способно исправить искажения, с которыми сигмоида не справляется, но требует больше данных и на маленькой выборке склонно переобучаться.
Преобразование-калибратор нельзя обучать на тех же данных, на которых обучалась сама модель: на обучающей выборке оценки модели слишком оптимистичны, и калибратор подстроится под них, а не под реальность. CalibratedClassifierCV решает это за вас, он использует кросс-валидацию, обучая модель и калибратор на разных фолдах.
И ещё, калибровка — монотонное преобразование: она меняет сами числа, но не их порядок. Поэтому AUC после калибровки не меняется.
Калибровать имеет смысл не всегда.
Калибровка нужна, когда вы используете вероятность как число: считаете ожидаемую выручку как произведение вероятности на сумму сделки, выбираете порог отсечения из цены ошибки, складываете или сравниваете выходы нескольких моделей, показываете пользователю «уверенность 87%». Во всех этих случаях важна не только величина оценки, но и её честность.
Калибровка не нужна, когда вы используете только порядок. Если задача — выбрать top-N лидов на обзвон или отранжировать выдачу, то берётся лишь взаимное расположение объектов, а его predict_proba передаёт верно даже без калибровки. Гнать такие предсказания через CalibratedClassifierCV смысла нет.
Вы делаете с вероятностью арифметику или только сравниваете и сортируете? Если арифметику — число обязано быть честным, и без калибровки не обойтись.
predict_proba внутри арифметического выражения — proba * выручка, ожидаемая стоимость, любое умножение на вероятность. Здесь нужны откалиброванные числа.
«Уверенность X%», показанная пользователю прямо из predict_proba — без калибровки этот процент почти наверняка неточен.
Модель выбрана и сравнивалась только по AUC, а её вероятности дальше используются как вероятности — AUC этого качества не проверял.
Случайный лес, бустинг или наивный Байес, чей predict_proba потребляется как вероятность без обёртки CalibratedClassifierCV и без проверки графиком надёжности — почти наверняка числа смещены.
Во всём проекте ни одного графика надёжности и ни одного Brier score, только AUC и accuracy — калибровку просто никто не смотрел.
predict_proba возвращает внутреннюю оценку уверенности модели, втиснутую в диапазон [0, 1]. Выглядит как вероятность, но модель не обещала, что это частота. Совпадает ли «0.9» с девяноста процентами — это калибровка, отдельное свойство, которым большинство моделей по умолчанию не обладает.
Поэтому пока вы только ранжируете объекты по оценке, всё в порядке — порядок predict_proba передаёт верно. Но как только вы начинаете делать с этим числом арифметику или показывать его как процент, сначала откалибруйте модель через CalibratedClassifierCV, а потом проверьте результат — графиком надёжности и Brier score, а не AUC.

Если хотите не просто получать от модели красивое число в predict_proba, а понимать, что с ним можно делать дальше, присмотритесь к открытым урокам:
1 июня, 18:00. «Оптимизируем построение модели через Pipeline». [4]
Преподаватель объяснит, как выстроить аккуратный ML‑процесс: от подготовки данных до обучения и проверки результата.
17 июня, 18:00. «Дерево решений — простой и интерпретируемый ML‑алгоритм». [5]
На уроке разберем базовый ML‑алгоритм, через который проще понять, как модель принимает решения и почему её предсказания важно правильно интерпретировать.
Уроки бесплатные и проходят в рамках онлайн‑курсов OTUS. Это возможность познакомиться с преподавателями‑практиками, протестировать формат обучения и задать вопросы.
А ещё подписывайтесь на канал OTUS в MAX [6] — там публикуем анонсы открытых уроков, полезные материалы и разборы для IT‑специалистов без лишнего шума.
Автор: badcasedaily1
Источник [7]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/30849
URLs in this post:
[1] ошибка: http://www.braintools.ru/article/4192
[2] случайность: http://www.braintools.ru/article/6560
[3] обучения: http://www.braintools.ru/article/5125
[4] «Оптимизируем построение модели через Pipeline».: https://otus.pw/iNh6/
[5] «Дерево решений — простой и интерпретируемый ML‑алгоритм».: https://otus.pw/ufct/
[6] канал OTUS в MAX: https://max.ru/otusru
[7] Источник: https://habr.com/ru/companies/otus/articles/1036882/?utm_campaign=1036882&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.