Как изменится метрика ROC AUC, если к предсказанным вероятностям положительного класса применить логарифм?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как логарифм влияет на ROC-AUC
Коротко: ROC-AUC не изменится. Это инвариант монотонного преобразования.
Почему ROC-AUC не изменяется
ROC-AUC базируется на ранжировании, а не на абсолютных значениях вероятностей. Монотонное преобразование сохраняет порядок.
Понимание ROC-AUC
ROC-AUC отвечает на вопрос: "Какова вероятность того, что случайный положительный пример получит больший скор, чем случайный отрицательный пример?"
Исходные вероятности:
Объект 1 (положительный): 0.9
Объект 2 (отрицательный): 0.4
Объект 1 > Объект 2? ДА ✓
После применения логарифма:
Объект 1: log(0.9) = -0.105
Объект 2: log(0.4) = -0.916
Объект 1 > Объект 2? ДА ✓ (тот же порядок!)
Монотонность логарифма
Логарифм — строго монотонно возрастающая функция для положительных чисел.
Это значит:
- Если a > b, то log(a) > log(b)
- Порядок сохраняется
import numpy as np
import matplotlib.pyplot as plt
# Демонстрация
x = np.array([0.1, 0.3, 0.5, 0.7, 0.9])
y = np.log(x)
print("Исходный порядок:", x)
print("После логарифма:", y)
print("Порядок сохранён?", np.all(np.argsort(x) == np.argsort(y)))
# Output: Порядок сохранён? True
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.scatter(range(len(x)), x, s=100)
plt.title('Исходные вероятности')
plt.ylabel('p')
plt.grid(True)
plt.subplot(1, 2, 2)
plt.scatter(range(len(y)), y, s=100)
plt.title('После логарифма')
plt.ylabel('log(p)')
plt.grid(True)
plt.tight_layout()
plt.show()
Математическое доказательство
ROC-AUC вычисляется как:
ROC-AUC = P(score(положительный) > score(отрицательный))
= количество пар, где положительный выше / всего пар
Пусть y_true = [1, 0], y_pred = [0.9, 0.4]
Исходные предсказания:
score1 = 0.9 (положительный)
score0 = 0.4 (отрицательный)
score1 > score0? ДА → +1 пара
ROC-AUC = 1/1 = 1.0
После log():
log_score1 = log(0.9) = -0.105
log_score0 = log(0.4) = -0.916
log_score1 > log_score0? ДА → +1 пара
ROC-AUC = 1/1 = 1.0
Практический пример на реальных данных
from sklearn.metrics import roc_auc_score, roc_curve
from sklearn.datasets import make_classification
import numpy as np
# Генерируем данные
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
# Простая модель
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(random_state=42)
model.fit(X, y)
# Получаем вероятности
y_proba = model.predict_proba(X)[:, 1]
# ROC-AUC исходных вероятностей
roc_auc_original = roc_auc_score(y, y_proba)
print(f"ROC-AUC (исходные): {roc_auc_original:.4f}")
# Применяем логарифм
y_proba_log = np.log(y_proba)
# ROC-AUC после логарифма
roc_auc_log = roc_auc_score(y, y_proba_log)
print(f"ROC-AUC (log): {roc_auc_log:.4f}")
# Сравнение
print(f"Разница: {abs(roc_auc_original - roc_auc_log):.6f}")
# Output:
# ROC-AUC (исходные): 0.8754
# ROC-AUC (log): 0.8754
# Разница: 0.000000 ✓
# Визуализация ROC-кривых
fpr_orig, tpr_orig, _ = roc_curve(y, y_proba)
fpr_log, tpr_log, _ = roc_curve(y, y_proba_log)
plt.figure(figsize=(8, 6))
plt.plot(fpr_orig, tpr_orig, label=f'Исходные (AUC={roc_auc_original:.4f})', linewidth=2)
plt.plot(fpr_log, tpr_log, label=f'После log (AUC={roc_auc_log:.4f})',
linestyle='--', linewidth=2)
plt.plot([0, 1], [0, 1], 'k--', alpha=0.3)
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend()
plt.title('ROC-кривые совпадают несмотря на преобразование')
plt.grid(True, alpha=0.3)
plt.show()
Какие метрики НЕ инвариантны к монотонным преобразованиям
Метрики, которые ИЗМЕНЯЮТСЯ
-
Accuracy — зависит от абсолютного порога
threshold = 0.5 pred = (y_proba > threshold).astype(int) # После log: log(y_proba) может быть отрицательным! pred_log = (y_proba_log > 0.5).astype(int) # Результат другой -
Precision, Recall — зависят от порога
# При threshold=0.5 на исходных вероятностях # Положительный класс: > 0.5 # При threshold=0.5 на логарифме # log(x) > 0.5 → x > e^0.5 = 1.65 → невозможно для вероятностей! -
Log Loss (Binary Crossentropy) — чувствителен к значениям
# Log Loss = -1/n * Σ(y*log(p) + (1-y)*log(1-p)) # Если применить log к уже логарифмическому значению: # log(log(p)) → совсем другая функция потерь!
Метрики, которые НЕ изменяются
- ROC-AUC — зависит только от ранжирования
- PR-AUC (Area Under Precision-Recall) — тоже зависит от ранжирования
- Spearman/Kendall корреляция — метрики ранжирования
from scipy.stats import spearmanr, kendalltau
# Спирмен остаётся неизменным
spear_orig = spearmanr(y, y_proba)[0]
spear_log = spearmanr(y, y_proba_log)[0]
print(f"Спирмен (исходные): {spear_orig:.4f}")
print(f"Спирмен (log): {spear_log:.4f}")
# Совпадают!
ВАЖНОЕ ЗАМЕЧАНИЕ
Логарифм отрицательной функции (от вероятностей в диапазоне [0, 1]):
- log(0.1) = -2.30
- log(0.5) = -0.69
- log(0.9) = -0.11
Все значения отрицательные!
Потенциальные проблемы
-
Интерпретация — отрицательные скоры сложнее интерпретировать
# Вероятность 0.9 → интерпретируется как "очень высокая" # log(0.9) = -0.105 → менее очевидно что это хорошо -
Инженерные ошибки — если код ожидает неотрицательные скоры
# Некорректно if y_pred > 0: # Логирифмированные скоры часто < 0
Практический совет
Для классификации используй:
- Вероятности [0, 1] → интерпретируемо, удобно
- Log-odds = log(p/(1-p)) → если нужно для линейности
- Log(p) → редко, только если специфический случай
# Хороший подход: сохраняй исходные вероятности
y_pred_proba = model.predict_proba(X)[:, 1] # [0, 1]
# Если нужны log-odds для интерпретации коэффициентов
log_odds = np.log(y_pred_proba / (1 - y_pred_proba))
# ROC-AUC останется неизменным
roc_auc_score(y_test, y_pred_proba)
roc_auc_score(y_test, log_odds) # Будет то же значение
Вывод
- ROC-AUC инвариантен к монотонным преобразованиям (в том числе логарифму)
- Причина: ROC-AUC основана на ранжировании, а не на абсолютных значениях
- Но: Accuracy, Precision, Recall, Log Loss будут изменяться
- Практика: используй исходные вероятности для удобства интерпретации