Перейти к содержанию

Шпаргалка: метрики ML

~6 минут чтения

Предварительно: Выбор модели | Подготовка к интервью

Выбор метрики -- это не техническое решение, а бизнес-решение. Метрика определяет, что модель оптимизирует, и неправильная метрика может сделать "хорошую" модель бесполезной. Эта шпаргалка -- decision framework: от типа задачи к конкретной метрике с обоснованием.

Дерево выбора метрики

graph TD
    START["Тип задачи?"] --> CLS["КЛАССИФИКАЦИЯ"]
    START --> REG["РЕГРЕССИЯ"]
    START --> RANK["РАНЖИРОВАНИЕ"]
    START --> CLUST["КЛАСТЕРИЗАЦИЯ"]

    CLS --> BIN["Бинарная?"]
    CLS --> MULTI["Многоклассовая?"]

    BIN --> BAL["Баланс классов<br/>Accuracy, F1"]
    BIN --> IMB["Дисбаланс<br/>F1, PR-AUC"]
    BIN --> FN_COST["FN дорого<br/>Recall, F2"]
    BIN --> FP_COST["FP дорого<br/>Precision, F0.5"]

    MULTI --> MACRO["Классы равны<br/>Macro F1"]
    MULTI --> WEIGHTED["Частые важнее<br/>Weighted F1"]

    REG --> BIG_ERR["Большие ошибки<br/>MSE, RMSE"]
    REG --> OUTLIER["Выбросы<br/>MAE, MedAE"]
    REG --> INTERP["Интерпретация<br/>MAPE, R2"]

    RANK --> ORDER["Порядок<br/>NDCG, MAP"]
    RANK --> FIRST["Первый результат<br/>MRR"]
    RANK --> TOPK["Top-K<br/>P@K, R@K"]

    CLUST --> LABELS_Y["Есть метки<br/>ARI, NMI"]
    CLUST --> LABELS_N["Нет меток<br/>Silhouette, DB"]

    style START fill:#e8eaf6,stroke:#3f51b5
    style CLS fill:#e8f5e9,stroke:#4caf50
    style REG fill:#fff3e0,stroke:#ef6c00
    style RANK fill:#f3e5f5,stroke:#9c27b0
    style CLUST fill:#fce4ec,stroke:#c62828

Classification Metrics

Confusion Matrix

                    Predicted
                 Negative  Positive
Actual Negative    TN        FP      ← Type I Error (ложная тревога)
       Positive    FN        TP      ← Type II Error (пропуск)
              Пропустили

Основные метрики

Метрика Формула Когда использовать
Accuracy (TP+TN)/(TP+TN+FP+FN) Сбалансированные классы
Precision TP/(TP+FP) Дорогие FP (спам, реклама)
Recall (Sensitivity) TP/(TP+FN) Дорогие FN (рак, фрод)
Specificity TN/(TN+FP) Важно не путать здоровых с больными
F1-Score 2·P·R/(P+R) Баланс Precision и Recall
F-beta (1+β²)·P·R/(β²·P+R) Настраиваемый баланс

Примеры бизнес-задач

МЕДИЦИНА (рак)
├── Recall важен: не пропустить больного
├── FN = пропущенный рак = ОЧЕНЬ ПЛОХО
└── Метрика: Recall, F2 (больше вес Recall)

СПАМ-ФИЛЬТР
├── Precision важен: не потерять важное письмо
├── FP = важное письмо в спаме = ПЛОХО
└── Метрика: Precision, F0.5 (больше вес Precision)

ФРОД-ДЕТЕКЦИЯ
├── Баланс: и пропустить плохо, и заблокировать хорошего плохо
├── Сильный дисбаланс классов
└── Метрика: PR-AUC, F1

РЕКОМЕНДАЦИИ
├── Precision@K: качество топ-K рекомендаций
└── Recall@K: покрытие интересов пользователя

Пороговые метрики

# ROC-AUC
from sklearn.metrics import roc_auc_score, roc_curve

y_prob = model.predict_proba(X_test)[:, 1]
roc_auc = roc_auc_score(y_test, y_prob)

fpr, tpr, thresholds = roc_curve(y_test, y_prob)

# PR-AUC (лучше для дисбаланса)
from sklearn.metrics import average_precision_score, precision_recall_curve

pr_auc = average_precision_score(y_test, y_prob)
precision, recall, thresholds = precision_recall_curve(y_test, y_prob)

Когда что использовать

Ситуация Метрика Почему
Сбалансированные классы Accuracy, F1 Работают хорошо
Дисбаланс 1:10 F1, ROC-AUC Accuracy врёт
Дисбаланс 1:100+ PR-AUC ROC-AUC оптимистичен
Нужен оптимальный порог ROC/PR кривые Видно trade-off
Сравнение моделей ROC-AUC, PR-AUC Не зависят от порога

Multiclass

from sklearn.metrics import f1_score

# Macro: среднее по классам (все классы равны)
f1_macro = f1_score(y_test, y_pred, average='macro')

# Weighted: взвешенное по размеру класса
f1_weighted = f1_score(y_test, y_pred, average='weighted')

# Micro: глобальный TP/FP/FN
f1_micro = f1_score(y_test, y_pred, average='micro')

Regression Metrics

Метрика Формула Интерпретация
MSE Σ(y-ŷ)²/n Средний квадрат ошибки
RMSE √MSE В единицах y
MAE Σ|y-ŷ|/n Средняя абсолютная ошибка
MAPE Σ|y-ŷ|/y·100% Процент ошибки
1 - SS_res/SS_tot Доля объяснённой дисперсии

Сравнение

MSE vs MAE:
├── MSE: сильнее штрафует большие ошибки
├── MAE: устойчивее к выбросам
└── Выбор зависит от задачи

RMSE vs MAE:
├── RMSE ≥ MAE всегда
├── Если RMSE >> MAE → много больших ошибок
└── Если RMSE ≈ MAE → ошибки равномерные

R² интерпретация:
├── R² = 1: идеальная модель
├── R² = 0: модель = среднее
├── R² < 0: модель хуже среднего
└── R² = 0.8: "модель объясняет 80% дисперсии"

Когда что использовать

Ситуация Метрика Почему
Нужна интерпретируемость MAE, MAPE Легко объяснить
Большие ошибки критичны MSE, RMSE Сильный штраф
Много выбросов MAE, MedAE Устойчивость
Сравнение разных таргетов R², MAPE Нормализованы
y близко к 0 MAE, RMSE MAPE взрывается
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

mse = mean_squared_error(y_test, y_pred)
rmse = mean_squared_error(y_test, y_pred, squared=False)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)

Ranking Metrics

Метрика Формула Когда использовать
Precision@K Relevant in top K / K Топ-K рекомендаций
Recall@K Relevant in top K / Total relevant Покрытие интересов
MAP Mean of AP across queries Общее качество поиска
MRR 1/rank первого релевантного Важен первый результат
NDCG DCG/IDCG Градуированная релевантность

NDCG подробнее

DCG = Σ (2^relevance - 1) / log2(position + 1)

Пример:
relevance = [3, 2, 3, 0, 1]
positions = [1, 2, 3, 4, 5]

DCG = (2³-1)/log2(2) + (2²-1)/log2(3) + (2³-1)/log2(4) + ...
    = 7/1 + 3/1.58 + 7/2 + 0 + 1/2.32
    = 7 + 1.89 + 3.5 + 0 + 0.43
    = 12.82

IDCG = DCG для идеального порядка
NDCG = DCG / IDCG

Clustering Metrics

Без истинных меток

Метрика Диапазон Лучше
Silhouette [-1, 1] Больше
Calinski-Harabasz [0, ∞) Больше
Davies-Bouldin [0, ∞) Меньше

С истинными метками

Метрика Диапазон Что измеряет
ARI [-1, 1] Согласованность с учётом случайности
NMI [0, 1] Mutual information, нормализованная
Homogeneity [0, 1] Кластеры содержат один класс
Completeness [0, 1] Класс в одном кластере
from sklearn.metrics import silhouette_score, adjusted_rand_score

# Без меток
silhouette = silhouette_score(X, labels)

# С метками
ari = adjusted_rand_score(y_true, labels)

NLP Metrics

Метрика Задача Что измеряет
Perplexity Language Model 2^(cross-entropy)
BLEU Translation n-gram совпадение с reference
ROUGE Summarization Recall n-gram
BERTScore Any generation Семантическое сходство
Exact Match QA Точное совпадение ответа
F1 (token) QA Overlap токенов

Computer Vision Metrics

Метрика Задача Формула
IoU Detection/Segmentation Intersection / Union
mAP Detection Mean AP at IoU thresholds
Dice Segmentation 2·|A∩B| / (|A|+|B|)
SSIM Image Quality Structural similarity
FID Generation Distance in feature space

Calibration Metrics

Модель калибрована, если P(y=1|p=0.8) ≈ 0.8

Метрики:
├── Brier Score = MSE для вероятностей (меньше лучше)
├── ECE = Expected Calibration Error
└── Reliability Diagram = визуальная проверка
from sklearn.calibration import calibration_curve
import matplotlib.pyplot as plt

fraction_of_positives, mean_predicted_value = calibration_curve(
    y_test, y_prob, n_bins=10
)

plt.plot(mean_predicted_value, fraction_of_positives, 's-')
plt.plot([0, 1], [0, 1], '--')  # Идеальная калибровка
plt.xlabel('Mean Predicted Probability')
plt.ylabel('Fraction of Positives')

Шпаргалка по sklearn

from sklearn.metrics import (
    # Classification
    accuracy_score,
    precision_score, recall_score, f1_score,
    roc_auc_score, average_precision_score,
    confusion_matrix, classification_report,
    log_loss,

    # Regression
    mean_squared_error,
    mean_absolute_error,
    r2_score,
    mean_absolute_percentage_error,

    # Clustering
    silhouette_score,
    adjusted_rand_score,
    normalized_mutual_info_score
)

# Classification
print(classification_report(y_test, y_pred))
print(f"ROC-AUC: {roc_auc_score(y_test, y_prob):.4f}")

# Regression
print(f"RMSE: {mean_squared_error(y_test, y_pred, squared=False):.4f}")
print(f"R²: {r2_score(y_test, y_pred):.4f}")

# Clustering
print(f"Silhouette: {silhouette_score(X, labels):.4f}")

Частые ошибки

Accuracy Paradox на дисбалансе

На датасете с 95% класса 0 и 5% класса 1, модель "всегда предсказывай 0" получит accuracy = 95%. Это не значит, что модель хорошая. Используй F1, PR-AUC или balanced accuracy вместо accuracy на несбалансированных данных.

ROC-AUC обманчив при сильном дисбалансе

ROC-AUC использует FPR = FP / (FP + TN). При огромном TN (99% негативных) даже большое количество FP дает маленький FPR. Используй PR-AUC — он не зависит от TN.

❌ R² для сравнения разных датасетов
   R² зависит от дисперсии таргета
   → Используй RMSE, MAE

❌ MAPE когда y близко к 0
   Деление на маленькие числа → взрыв
   → Используй sMAPE или MAE

❌ Оптимизация одной метрики
   Можно переоптимизировать в ущерб другим
   → Смотри на несколько метрик

Самопроверка: какую метрику выбрать?

Вы строите модель для банка, которая решает выдавать ли кредит. Одобрение мошенника = потеря $50K. Отказ хорошему клиенту = потеря $500 дохода. Fraud rate = 2%. (1) Какую метрику оптимизировать? (2) Почему accuracy не подойдёт? (3) Как выбрать порог?

Подсказки: (1) FN стоит 100x дороже FP, (2) accuracy при 2% fraud = 98% "always approve", (3) cost-sensitive threshold: порог где expected cost минимален.


Вопросы для собеседования

Датасет с 1% fraud. Модель дает accuracy 99%. Хорошая ли модель? Какую метрику выбрать?

❌ «99% accuracy = отличная модель» -- модель может просто предсказывать "не фрод" для всех. accuracy = 99% при 1% fraud rate означает zero recall.

✅ Нет -- модель-константа ("всегда не фрод") даст accuracy 99%. Нужно: (1) Recall -- сколько фродов поймали (при 0% recall модель бесполезна), (2) PR-AUC -- не зависит от TN (которых 99%), (3) F1 или F2 -- если пропуск фрода дороже false alarm. ROC-AUC тоже будет завышен из-за огромного TN в знаменателе FPR. На практике: бизнес задает cost matrix (FN = потеря $50K, FP = звонок клиенту = $5), по ней считается optimal threshold.

В чем разница между ROC-AUC и PR-AUC? Когда каждый лучше?

❌ «ROC-AUC всегда лучше, потому что он стандартный» -- не учитывает дисбаланс.

✅ ROC: ось X = FPR = FP/(FP+TN), ось Y = TPR = TP/(TP+FN). При дисбалансе 1:1000 огромный TN делает FPR почти нулевым даже при большом FP -- кривая выглядит хорошо. PR-AUC: ось X = Recall = TP/(TP+FN), ось Y = Precision = TP/(TP+FP). Precision не использует TN, поэтому дисбаланс не маскирует ошибки. Правило: ROC-AUC при дисбалансе до 1:10, PR-AUC при 1:100+. Для сравнения моделей -- оба, но PR-AUC более информативен на реальных данных с дисбалансом.

NDCG = 0.85. Как интерпретировать? Какие ограничения у этой метрики?

❌ «0.85 из 1.0, значит 85% правильно» -- упрощение, не учитывает нюансы.

✅ NDCG = DCG/IDCG = 85% от идеального ранжирования. DCG = \(\sum_i \frac{2^{rel_i} - 1}{\log_2(i+1)}\) -- позиция и релевантность взвешены логарифмически, ошибки вверху списка штрафуются сильнее. Ограничения: (1) Не различает "плохой топ + хороший хвост" от "хороший топ + плохой хвост" при одинаковом NDCG. Для поиска первый результат критичен -- используй NDCG@K с малым K. (2) Требует градуированную релевантность (0-3), а не бинарную. (3) Не учитывает позицию просмотра пользователем (cascade model). Дополняй MRR (первый релевантный) и MAP (средняя precision).


Источники

  1. sklearn.metrics -- Classification metrics
  2. sklearn.metrics -- Regression metrics
  3. Jesse Davis, Mark Goadrich -- "The Relationship Between Precision-Recall and ROC Curves" (ICML 2006) -- обоснование PR-AUC при дисбалансе
  4. Kalervo Jarvelin, Jaana Kekalainen -- "Cumulated Gain-Based Evaluation of IR Techniques" (ACM TOIS 2002) -- оригинал NDCG

See Also