Что будет с ROC-AUC, если умножить все предсказанные вероятности на 2?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Отличный вопрос, который проверяет понимание ROC-AUC! Коротко: ROC-AUC останется неизменной. Давайте разберёмся почему и докажем это математически.
Что такое ROC-AUC
ROC-AUC (Area Under the Receiver Operating Characteristic Curve) — это площадь под кривой, которая показывает зависимость True Positive Rate от False Positive Rate при разных пороговых значениях.
Ключевое свойство: ROC-AUC инвариантна к монотонным преобразованиям
import numpy as np
from sklearn.metrics import roc_auc_score, roc_curve
import matplotlib.pyplot as plt
# Исходные вероятности
y_test = np.array([0, 0, 0, 1, 1, 1])
y_proba = np.array([0.1, 0.2, 0.3, 0.6, 0.7, 0.9])
# Оригинальный ROC-AUC
roc_auc_original = roc_auc_score(y_test, y_proba)
print(f"ROC-AUC (оригинальные вероятности): {roc_auc_original:.4f}")
# Умножим на 2 (будут > 1)
y_proba_scaled = y_proba * 2
roc_auc_scaled = roc_auc_score(y_test, y_proba_scaled)
print(f"ROC-AUC (умноженные на 2): {roc_auc_scaled:.4f}")
# Проверка: они равны
print(f"\nРавны ли ROC-AUC? {np.isclose(roc_auc_original, roc_auc_scaled)}")
# Можно умножить на любое число > 0
for multiplier in [0.5, 1.5, 3, 10, 100]:
y_proba_mult = y_proba * multiplier
roc_auc_mult = roc_auc_score(y_test, y_proba_mult)
print(f"Множитель {multiplier:3}: ROC-AUC = {roc_auc_mult:.4f}")
Почему ROC-AUC не изменяется
ROC-AUC зависит только от ранжирования (ranking) предсказаний, а не от их абсолютных значений.
Визуализация
# Построим ROC-кривые
fpr_orig, tpr_orig, thresholds_orig = roc_curve(y_test, y_proba)
fpr_scaled, tpr_scaled, thresholds_scaled = roc_curve(y_test, y_proba_scaled)
plt.figure(figsize=(10, 6))
plt.plot(fpr_orig, tpr_orig, label=f"Original (AUC={roc_auc_original:.4f})", linewidth=2)
plt.plot(fpr_scaled, tpr_scaled, label=f"Scaled x2 (AUC={roc_auc_scaled:.4f})",
linestyle="--", linewidth=2, alpha=0.7)
plt.plot([0, 1], [0, 1], "k--", alpha=0.3, label="Random")
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC Curves: Original vs Scaled x2")
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
# Кривые совпадают!
Математическое доказательство
ROC-AUC как вероятность
ROC-AUC можно интерпретировать как вероятность того, что модель правильно ранжирует случайный пример положительного класса выше случайного примера отрицательного класса:
ROC-AUC = P(score_positive > score_negative)
Если умножить все оценки на константу k > 0:
ROC-AUC' = P(k * score_positive > k * score_negative)
= P(score_positive > score_negative) [т.к. k > 0]
= ROC-AUC
Пороговые значения
РОК-кривая создаётся по разным пороговым значениям:
# Для каждого порога считаем TPR и FPR
for threshold in [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]:
pred_orig = (y_proba >= threshold).astype(int)
tp = np.sum((pred_orig == 1) & (y_test == 1))
fp = np.sum((pred_orig == 1) & (y_test == 0))
fn = np.sum((pred_orig == 0) & (y_test == 1))
tn = np.sum((pred_orig == 0) & (y_test == 0))
tpr = tp / (tp + fn) if (tp + fn) > 0 else 0
fpr = fp / (fp + tn) if (fp + tn) > 0 else 0
# Для масштабированных вероятностей порог тоже масштабируется
threshold_scaled = threshold * 2
pred_scaled = (y_proba_scaled >= threshold_scaled).astype(int)
# Предсказания одинаковые!
print(f"Порог {threshold}: одинаковые предсказания? {np.array_equal(pred_orig, pred_scaled)}")
Что ИЗМЕНИТСЯ при умножении?
1. Пороги (thresholds)
Пороги в ROC-кривой будут другими:
fpr, tpr, thresholds = roc_curve(y_test, y_proba)
print(f"Оригинальные пороги: {thresholds}")
print(f"Минимальный: {thresholds.min():.4f}")
print(f"Максимальный: {thresholds.max():.4f}")
fpr_s, tpr_s, thresholds_s = roc_curve(y_test, y_proba_scaled)
print(f"\nМасштабированные пороги: {thresholds_s}")
print(f"Минимальный: {thresholds_s.min():.4f}")
print(f"Максимальный: {thresholds_s.max():.4f}")
# Пороги масштабируются, но ROC-кривая остаётся той же!
2. Если вероятности > 1
В примере выше y_proba * 2 даст значения > 1, что нарушает интерпретацию как вероятности:
print(f"Масштабированные вероятности: {y_proba_scaled}")
# [0.2, 0.4, 0.6, 1.2, 1.4, 1.8] — это не валидные вероятности!
# Но ROC-AUC всё равно работает корректно
Другие метрики, которые ИЗМЕНЯТСЯ
Вот здесь важно быть осторожным:
Log Loss (cross-entropy) — ИЗМЕНИТСЯ
from sklearn.metrics import log_loss
log_loss_original = log_loss(y_test, y_proba)
log_loss_scaled = log_loss(y_test, np.clip(y_proba_scaled, 1e-10, 1-1e-10))
print(f"Log Loss (оригинал): {log_loss_original:.4f}")
print(f"Log Loss (масштабированный): {log_loss_scaled:.4f}")
print(f"Равны? {np.isclose(log_loss_original, log_loss_scaled)}")
# Нет! Log Loss изменится
Brier Score — ИЗМЕНИТСЯ
from sklearn.metrics import brier_score_loss
brier_original = brier_score_loss(y_test, y_proba)
brier_scaled = brier_score_loss(y_test, np.clip(y_proba_scaled, 0, 1))
print(f"Brier Score (оригинал): {brier_original:.4f}")
print(f"Brier Score (масштабированный): {brier_scaled:.4f}")
print(f"Равны? {np.isclose(brier_original, brier_scaled)}")
# Нет!
Практический пример
# Реальный сценарий: модель выдаёт логиты вместо вероятностей
logits = np.array([-2.0, -1.0, 0.0, 1.0, 2.0, 3.0])
y_test = np.array([0, 0, 0, 1, 1, 1])
# Вероятности
y_proba = 1 / (1 + np.exp(-logits)) # sigmoid
roc_auc_proba = roc_auc_score(y_test, y_proba)
roc_auc_logits = roc_auc_score(y_test, logits) # Можно передать логиты!
print(f"ROC-AUC (вероятности): {roc_auc_proba:.4f}")
print(f"ROC-AUC (логиты): {roc_auc_logits:.4f}")
print(f"Равны? {np.isclose(roc_auc_proba, roc_auc_logits)}")
# Да! Потому что ROC-AUC зависит только от ранжирования
Ключевые выводы
-
ROC-AUC инвариантна к положительным монотонным преобразованиям (умножение на любое число > 0, логарифм, возведение в степень)
-
Это верно для всех метрик на основе ранжирования: Precision@K, MRR, NDCG и т.д.
-
Другие метрики чувствительны к масштабированию: Log Loss, Brier Score, Calibration error
-
Пороги изменятся, но ROC-кривая останется той же
-
Практический совет: если хотите калиброванные вероятности (чтобы 0.7 действительно означало 70% уверенность), умножение разрушит калибровку. Но для ранжирования (выдачи топ-N) это не важно.
Это демонстрирует, почему ROC-AUC часто предпочитается для задач ранжирования, даже если вероятности не совсем валидны.