Для студента Data Science здесь происходит очень важный сдвиг мышления. Мы перестаем спрашивать: “Сколько процентов модель угадала вообще?” и начинаем спрашивать: “Что именно происходит с редким, но значимым классом, когда я двигаю порог?”. Precision-recall curve как раз и показывает этот живой конфликт между желанием находить больше положительных объектов и желанием не засорять систему ложными тревогами.
Эта тема особенно важна в 2026 году, потому что модели все чаще работают в средах, где решение не заканчивается предсказанием. Дальше включаются люди, процессы, очереди на проверку, лимиты на обзвон, стоимость ошибки и репутационный риск. PR-кривая помогает увидеть не только поведение модели, но и форму будущей нагрузки на систему вокруг нее.
Эта тема особенно важна в 2026 году, потому что модели все чаще работают в средах, где решение не заканчивается предсказанием. Дальше включаются люди, процессы, очереди на проверку, лимиты на обзвон, стоимость ошибки и репутационный риск. PR-кривая помогает увидеть не только поведение модели, но и форму будущей нагрузки на систему вокруг нее.
Почему accuracy в задачах редких классов почти всегда слишком оптимистична
Представим выборку, где положительный класс занимает один процент. Если модель всегда говорит “нет события”, она получит accuracy около 99 процентов. На бумаге это выглядит великолепно. На практике такая система ничего не умеет: она просто капитулировала перед дисбалансом классов.
Вот почему при редких событиях нас интересуют не все правильные ответы сразу, а структура ошибок вокруг положительного класса. Нас волнует, сколько полезных объектов модель действительно подняла и насколько можно доверять тем объектам, которые она пометила как положительные. То есть разговор неизбежно переходит к precision и recall.
И как только эта логика становится понятной, рядом уже полезно сравнить её с более общей оптикой через ROC-AUC и PR-AUC, чтобы не путать ranking quality со стоимостью реального потока положительных решений.
Сначала нужно понять, что именно измеряют precision и recall
Обе метрики рождаются из одной confusion matrix, но отвечают на разные вопросы.
(\mathrm{Precision}=\frac{\mathrm{TP}}{\mathrm{TP}+\mathrm{FP}})
Раздел математики: математическая статистика.
Что означает каждый символ:
(\mathrm{TP}) — true positives, число объектов, которые модель правильно назвала положительными.
(\mathrm{FP}) — false positives, число объектов, которые модель ошибочно подняла как положительные.
Эта формула появляется из вопроса: “Если система уже сработала, можно ли ей верить?”.
Роль precision в алгоритме прикладная: она контролирует чистоту потока положительных решений.
Численный пример: если модель пометила как положительные (40) объектов, а реально полезными из них оказались только (12), то (\mathrm{TP}=12), (\mathrm{FP}=28), и precision равен (\frac{12}{12+28}=0.3). То есть только 30 процентов тревог действительно полезны.
(\mathrm{Recall}=\frac{\mathrm{TP}}{\mathrm{TP}+\mathrm{FN}})
Раздел математики: математическая статистика.
Что означает каждый символ:
(\mathrm{FN}) — false negatives, положительные объекты, которые система пропустила.
Эта формула появляется из вопроса: “Если в данных действительно есть важный положительный объект, какова вероятность, что модель его вообще поднимет?”.
Роль recall в алгоритме связана с полнотой охвата редкого класса.
Численный пример: если в тесте было (60) настоящих положительных объектов, а модель нашла только (12), то (\mathrm{FN}=48), и recall равен (\frac{12}{12+48}=0.2). Это значит, что система подняла лишь 20 процентов действительно важных случаев.
Именно здесь и появляется напряжение. Если мы хотим поднять больше настоящих положительных объектов, порог часто приходится снижать. Recall растет. Но вместе с ним растет и число ложных тревог, а значит precision падает. PR-кривая — это карта этого конфликта.
Что такое PR-кривая на интуитивном языке
Представьте, что классификатор выдает не сразу класс, а score уверенности. Мы можем поставить жесткий порог и признавать положительными только самые уверенные объекты. Тогда положительных решений станет мало, зато они будут сравнительно “чистыми”. Если порог опустить, система станет агрессивнее: recall вырастет, потому что модель начнет забирать больше редких событий. Но в поток попадут и объекты, которые на самом деле отрицательны. Precision начнет снижаться.
Каждый порог — это отдельная рабочая точка модели. Precision-recall curve просто соединяет все такие точки в одно пространство. Поэтому она показывает не “качество модели вообще”, а целое семейство режимов, в которых эта модель может жить.
Геометрический смысл PR-кривой
Геометрически PR-кривая живет в плоскости, где по оси (x) откладывается recall, а по оси (y) — precision. Каждая точка — это конкретный порог. Когда мы двигаемся вдоль кривой, мы не переобучаем модель и не меняем ее веса. Мы меняем только decision rule: насколько охотно система будет говорить “да”.
Это и есть геометрия выбора рабочего режима. В верхней правой части плоскости хотелось бы оказаться всем, потому что там и recall высокий, и precision высокий. Но реальная модель редко дает такой подарок. Обычно приходится выбирать: или система становится осторожной, или начинает ловить больше редких событий ценой шума.
В прикладном смысле это очень похоже на инженерную панель с двумя ручками. Одна ручка отвечает за полноту охвата, другая — за чистоту сигнала. Порог двигает обе одновременно.
Почему baseline для PR-кривой устроен иначе, чем многие ожидают
В задачах с редкими классами очень важно помнить о базовой доле положительного класса. Случайная модель не будет иметь “средний precision 0.5”. Ее базовый precision равен просто доле положительного класса в данных.
(\mathrm{Baseline}=\frac{\mathrm{P}}{\mathrm{P}+\mathrm{N}})
Раздел математики: вероятность и математическая статистика.
Что означает каждый символ:
(\mathrm{P}) — число положительных объектов.
(\mathrm{N}) — число отрицательных.
Эта величина появляется как ожидаемый precision случайного отбора положительных объектов.
Для ML это важный ориентир: без него легко недооценить модель, которая работает в среде с очень низким base rate.
Численный пример: если в выборке (\mathrm{P}=100) положительных и (\mathrm{N}=4900) отрицательных объектов, то baseline precision равен (\frac{100}{5000}=0.02). Значит, модель с precision 0.14 уже работает в семь раз лучше случайного уровня.
Именно поэтому PR-кривая особенно честна при редких классах. Она не позволяет забыть, насколько низка исходная вероятность положительного события.
Где здесь появляется связь с оптимизацией
В классическом обучении модели мы минимизируем некоторую loss function. Но после обучения остается еще одна отдельная optimization-задача: какой порог выбрать? Формально веса модели уже зафиксированы, однако бизнес-решение еще не принято. Мы все еще ищем точку на PR-кривой, где система будет вести себя лучше для конкретной цены ошибок.
Например, в антифроде ложный пропуск может стоить дорого, но и ложная блокировка тоже бьет по продукту. В медицинском скрининге recall часто важнее, потому что пропустить болезнь опасно, но при слишком низком precision врачи утонут в ложных сигналах. То есть оптимизация продолжается уже не в пространстве весов модели, а в пространстве порогов и операционных ограничений.
Когда одной PR-кривой мало и нужен F-бета
Иногда хочется получить не всю кривую, а одну численную точку, которая отражает предпочтительный баланс между precision и recall. Для этого используют семейство F-метрик. Они не заменяют PR-кривую, но помогают выбрать рабочий порог.
(F_{\beta}=(1+\beta^2)\frac{\mathrm{Precision}\cdot \mathrm{Recall}}{\beta^2\cdot \mathrm{Precision}+\mathrm{Recall}})
Раздел математики: математическая статистика и прикладная оптимизация.
Что означает каждый символ:
(\beta) — коэффициент, задающий, чему мы придаем больший вес.
Если (\beta>1), сильнее ценится recall.
Если (\beta<1), сильнее ценится precision.
Формула появляется из задачи объединить две метрики в одну так, чтобы явно контролировать приоритеты.
Численный пример: пусть precision равен (0.4), recall равен (0.8), а мы берем (\beta=2), потому что нам важнее полнота. Тогда (F_2=5\cdot\frac{0.4\cdot0.8}{4\cdot0.4+0.8}=5\cdot\frac{0.32}{2.4}\approx0.667). Это число уже учитывает, что recall для нас важнее precision.
Для Data Science это полезно тем, что кривую можно использовать как карту, а F-бета — как правило выбора рабочей точки на этой карте. Но окончательное решение почти всегда требует ещё одного шага: понять, какой threshold действительно делает модель рабочей в продакшене, а не просто красивой в ноутбуке.
Что именно анализирует PR-кривая в production-задаче
Она показывает, насколько дорогим окажется каждый дополнительный пойманный положительный случай. Если recall растет, а precision резко обрушивается, значит система начинает покупать каждый новый true positive слишком большим числом ложных тревог. Если recall почти не растет даже при сильном снижении порога, значит ранжирование модели само по себе слабое: она не умеет выстраивать редкий класс в верхнюю часть списка.
Это очень важное наблюдение. Иногда проблема не в пороге, а в том, что score модели плохо сортирует объекты. Тогда никакая игра с decision threshold уже не спасет ситуацию, и вопрос нужно переносить в сторону переобучения, признаков или loss function. В задачах с тяжёлым дисбалансом это часто означает, что одной настройки метрик мало и нужно отдельно смотреть, как class weights и rebalancing меняют саму механику обучения.
Python: как строить PR-кривую и выбирать порог
from sklearn.datasets import make_classification # Генерируем синтетическую задачу с дисбалансом классов.
from sklearn.model_selection import train_test_split # Подключаем разбиение на train и test.
from sklearn.linear_model import LogisticRegression # Берем логистическую регрессию как базовый классификатор.
from sklearn.metrics import precision_recall_curve, average_precision_score # Импортируем функции для PR-анализа.
import numpy as np # Numpy нужен для выбора лучшего порога по F1.
X, y = make_classification( # Создаем искусственную бинарную задачу.
n_samples=6000, # Генерируем шесть тысяч объектов.
n_features=25, # Используем двадцать пять признаков.
n_informative=7, # Делаем семь признаков действительно полезными.
n_redundant=3, # Добавляем несколько коррелированных признаков.
weights=[0.97, 0.03], # Положительный класс занимает только 3 процента.
class_sep=1.2, # Управляем разделимостью классов.
random_state=42, # Фиксируем случайность для воспроизводимости.
) # Получаем признаки и target.
X_train, X_test, y_train, y_test = train_test_split( # Делим данные на train и test.
X, y, test_size=0.2, stratify=y, random_state=42
) # Сохраняем долю редкого класса в обеих частях.
model = LogisticRegression(max_iter=1000) # Создаем модель с увеличенным лимитом итераций.
model.fit(X_train, y_train) # Обучаем классификатор на train-части.
scores = model.predict_proba(X_test)[:, 1] # Получаем вероятности положительного класса.
precision, recall, thresholds = precision_recall_curve(y_test, scores) # Строим набор точек PR-кривой.
ap = average_precision_score(y_test, scores) # Считаем Average Precision как площадь под кривой в sklearn-логике.
f1_values = 2 * precision[:-1] * recall[:-1] / (precision[:-1] + recall[:-1] + 1e-12) # Считаем F1 для всех порогов.
best_idx = np.argmax(f1_values) # Находим индекс порога с максимальным F1.
best_threshold = thresholds[best_idx] # Достаем лучший по F1 порог.
print("Average Precision:", round(ap, 4)) # Печатаем aggregate-оценку кривой.
print("Best threshold by F1:", round(best_threshold, 4)) # Печатаем найденный порог.
print("Precision at best threshold:", round(precision[best_idx], 4)) # Смотрим precision в этой точке.
print("Recall at best threshold:", round(recall[best_idx], 4)) # Смотрим recall в этой точке.Этот пример полезен не тем, что “строит еще одну метрику”, а тем, что показывает реальный рабочий цикл. Сначала мы обучаем модель. Потом берем вероятности. Затем смотрим всю PR-кривую и только после этого решаем, какой порог делать рабочим. То есть анализ происходит поверх ранжирования модели, а не вместо него.
Что часто делают неправильно
Самая частая ошибка — выбрать порог по привычке, например 0.5, и никогда не возвращаться к нему с точки зрения метрик. Вторая ошибка — смотреть только на Average Precision и не смотреть на саму кривую. Третья — сравнивать precision разных задач без учета base rate. Precision 0.2 в одном домене может быть провалом, а в другом — очень сильным результатом, если положительные события там экстремально редки.
Еще одна ошибка — забывать, что PR-кривая оценивает ранжирование при разных порогах, но не говорит сама по себе, сколько реально будет стоить каждое решение. То есть ее обязательно нужно связывать с производственным контекстом, а не читать как чисто академический объект.
А если сами вероятности модели ещё и плохо калиброваны, то кривая не исчезает, но интерпретация порога становится куда опаснее. Поэтому рядом полезно держать и материал о том, почему score модели не всегда совпадает с реальной вероятностью события.
Что важно вынести из темы
Precision-recall curve — это инструмент для задач, где редкий положительный класс важнее красивой общей статистики. Она показывает, как меняется чистота положительных решений и полнота охвата редкого класса при движении порога. Геометрически это карта режимов одной и той же модели. Практически — мост между вероятностным score и реальным действием системы.
Если сформулировать совсем коротко, PR-кривая отвечает на вопрос: что именно мы платим за каждый дополнительный найденный положительный объект? И именно поэтому она так полезна там, где положительный класс редкий, а цена ошибки высока.
Kaggle notebook по теме:
https://www.kaggle.com/code/robinteuwens/precision-vs-recall-optimizing-fraud-costs