Условие
Для каждой ситуации выберите целевую метрику и объясните выбор:
- Антифрод: 0.1% мошеннических транзакций, 99.9% — нормальные.
- Скрининг рака: важно не пропустить больного.
- Спам-фильтр: нельзя положить «нормальное» письмо в спам.
- Ранжирование товаров в выдаче.
- Кредитный скоринг: фиксированный лимит одобрений (10% заявок).
Решение
Глоссарий
- Precision = TP / (TP + FP). «Из того, что назвали положительным, сколько реально положительных».
- Recall = TP / (TP + FN). «Из всех реально положительных, сколько поймали».
- F1 = 2·P·R / (P+R). Гармоническое среднее, когда нужны оба.
- ROC-AUC — вероятность, что случайный положительный будет проранжирован выше случайного отрицательного. Инвариантна к threshold.
- PR-AUC — площадь под PR-кривой, важна при сильном дисбалансе.
По кейсам
1. Антифрод (1:1000): accuracy бесполезна (99.9% даёт «всё нормальное»). Цена FP — ручная проверка / отказ клиенту; FN — деньги. Обычно фиксируют ограниченный budget оператора (например, 1000 кейсов в день) → метрика Precision@K или Recall@FPR=0.01. На обучении — PR-AUC (устойчива к дисбалансу).
2. Скрининг рака: FN — пропустили больного → смерть. FP — направили здорового на дополнительные тесты, дёшево. → Recall (sensitivity) при ограничении FPR/specificity на разумном уровне. На обучении — ROC-AUC.
3. Спам: FP (нормальное → спам) дорого; FN (спам → почта) дёшево. → Precision при минимальном пороге Recall (например, ≥0.9).
4. Ранжирование: не «спам/не спам», а порядок. Метрики NDCG@k, MRR, MAP. ROC-AUC можно использовать как proxy, если задача — pointwise бинарь «кликнут / нет».
5. Скоринг с лимитом одобрений: одобрить только top-10% самых надёжных. Threshold не важен — важен ранжирующий порядок топ-10%. → Precision@10% или Gini (= 2·AUC − 1). Дополнительно бизнес-метрики: ожидаемый дефолт / маржа.
Иллюстрация на коде
from sklearn.metrics import (precision_score, recall_score, f1_score,
roc_auc_score, average_precision_score)
import numpy as np
# дисбалансная задача
y_true = np.array([0]*999 + [1]) # 1 положительный из 1000
y_pred1 = np.zeros(1000) # «всё нормальное»
y_pred2 = (np.random.rand(1000) > 0.5).astype(int)
print("acc (всё 0) :", (y_pred1 == y_true).mean()) # 0.999
print("recall :", recall_score(y_true, y_pred1)) # 0.0→ accuracy = 99.9% при нулевом recall = бесполезный результат.
Threshold tuning
ROC/PR-кривые — оценка модели до выбора порога. Дальше выбираем threshold под бизнес-ограничение:
from sklearn.metrics import precision_recall_curve
p, r, thr = precision_recall_curve(y_true, y_scores)
# fix recall >= 0.8 → max precision
mask = r >= 0.8
best = mask & (p == p[mask].max())
print("threshold:", thr[best][0], "P:", p[best][0], "R:", r[best][0])Подводные камни
- Accuracy на дисбалансе — почти всегда ловушка.
- ROC-AUC на сильном дисбалансе оптимистичен; PR-AUC честнее (отражает FP среди отрицательных).
- F1 = «золотая середина» — мифична: бизнесу обычно нужна одна сторона (точность или полнота), а не их гармоника.
- MCC (Matthews correlation) — устойчив к дисбалансу, хорошая альтернатива F1.
- Калибровка вероятностей: модель может ранжировать отлично, но
pне равен реальной вероятности → Brier /calibration_curve. Важно для скоринга. - AUC на разных подмножествах (по сегментам) часто проседает — модель училась на «среднем».
- Метрика обучения ≠ метрика бизнеса: ROC-AUC обучения не равна $-эффекту. Считать gain matrix (Profit Curve).
Эталонный ответ
- Антифрод — PR-AUC + Recall@FPR / Precision@K (cost-sensitive).
- Рак — Recall (sensitivity) при контроле specificity; обучение по ROC-AUC.
- Спам — Precision при минимальном Recall.
- Ранжирование — NDCG@k / MRR.
- Скоринг с фиксированным лимитом — Precision@10% / Gini, плюс калибровка вероятностей.
Главное — не «лучшая универсальная метрика», а метрика, соответствующая бизнес-стоимости ошибок FP и FN.