Зависит ли ROC AUC от распределения классов
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Зависит ли ROC AUC от распределения классов?
Ответ: НЕТ, ROC AUC (Receiver Operating Characteristic Area Under Curve) практически НЕ зависит от дисбаланса классов.
Это главное преимущество ROC AUC перед другими метриками (такими как Accuracy). Давайте разберём почему.
Что такое ROC AUC?
ROC кривая показывает зависимость между:
- True Positive Rate (TPR, Recall) — какую долю положительных примеров модель нашла
- False Positive Rate (FPR) — какую долю отрицательных примеров модель неправильно классифицировала как положительные
TPR = TP / (TP + FN) — сколько из реальных 1 мы угадали
FPR = FP / (FP + TN) — сколько из реальных 0 мы неправильно назвали 1
ROC кривая строится независимо от общего распределения классов. Вот почему:
Почему ROC AUC не зависит от дисбаланса?
Пример: Задача - обнаружение мошенничества
Предположим:
- 1% транзакций — мошеннические (positive)
- 99% транзакций — честные (negative)
Модель выдаёт вероятности для каждой транзакции. Мы можем менять порог классификации:
Порог = 0.5: классифицируем как мошенничество если P > 0.5
Порог = 0.3: классифицируем как мошенничество если P > 0.3
Порог = 0.9: классифицируем как мошенничество если P > 0.9
Для каждого порога вычисляем TPR и FPR, затем строим кривую ROC.
from sklearn.metrics import roc_curve, roc_auc_score
from sklearn.datasets import make_classification
import numpy as np
# Создадим сильно дисбалансированный набор
X, y = make_classification(
n_samples=1000,
weights=[0.99, 0.01], # 99% класс 0, 1% класс 1
random_state=42
)
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X, y)
y_pred_proba = model.predict_proba(X)[:, 1]
# ROC AUC НЕ зависит от дисбаланса
roc_auc = roc_auc_score(y, y_pred_proba)
print(f"ROC AUC = {roc_auc:.3f}") # честная оценка качества
# Сравним с Accuracy
from sklearn.metrics import accuracy_score
y_pred = (y_pred_proba > 0.5).astype(int)
accuracy = accuracy_score(y, y_pred)
print(f"Accuracy = {accuracy:.3f}") # может быть 99% просто всегда предсказывая 0!
Математическое объяснение
ROC AUC вычисляется как вероятность того, что модель выдаст более высокую вероятность для случайно выбранного положительного примера, чем для случайно выбранного отрицательного:
ROC AUC = P(score(positive) > score(negative))
Эта вероятность НЕ зависит от того, сколько всего положительных и отрицательных примеров. Она зависит только от способности модели различать классы.
Практический пример
from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as plt
# Данные с дисбалансом 99:1
from sklearn.datasets import make_classification
# Сценарий 1: 99:1
X1, y1 = make_classification(
n_samples=10000,
weights=[0.99, 0.01],
random_state=42
)
# Сценарий 2: 50:50 (сбалансированные)
X2, y2 = make_classification(
n_samples=10000,
weights=[0.5, 0.5],
random_state=42
)
model = LogisticRegression()
# Тестируем на дисбалансированных данных
model.fit(X1, y1)
y_pred1 = model.predict_proba(X1)[:, 1]
roc_auc1 = roc_auc_score(y1, y_pred1)
# Тестируем на сбалансированных данных
model.fit(X2, y2)
y_pred2 = model.predict_proba(X2)[:, 1]
roc_auc2 = roc_auc_score(y2, y_pred2)
print(f"ROC AUC (99:1 дисбаланс) = {roc_auc1:.3f}")
print(f"ROC AUC (50:50 баланс) = {roc_auc2:.3f}")
# Оба значения примерно одинаковые для одной и той же модели!
Когда ROC AUC может быть проблематичной?
1. Экстремный дисбаланс
Если положительных примеров меньше 0.1%, ROC AUC может быть неполным инструментом, потому что FPR вычисляется на малом количестве отрицательных примеров. Лучше использовать Precision-Recall AUC.
from sklearn.metrics import precision_recall_curve, auc
precision, recall, _ = precision_recall_curve(y, y_pred_proba)
pr_auc = auc(recall, precision)
print(f"PR AUC = {pr_auc:.3f}") # часто лучше для дисбаланса
2. Высокие требования к специфичности
Если нас волнует не общее качество, а конкретная метрика (например, не более 1% false positives), нужно смотреть на конкретной точке ROC кривой, не на общий AUC.
Сравнение метрик при дисбалансе
# Модель просто всегда предсказывает отрицательный класс
from sklearn.metrics import accuracy_score, precision_score, recall_score
y_true = [0, 0, 0, 0, 0, 0, 0, 0, 0, 1] # 90% нули, 10% единицы
y_pred = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # всегда предсказываем 0
print(f"Accuracy = {accuracy_score(y_true, y_pred):.1%}") # 90% (кажется хорошо!)
print(f"Precision = {precision_score(y_true, y_pred, zero_division=0):.1%}") # нет смысла
print(f"Recall = {recall_score(y_true, y_pred):.1%}") # 0% (не находим положительные)
# ROC AUC покажет 0 (худшее значение)
roc_auc = roc_auc_score(y_true, y_pred)
print(f"ROC AUC = {roc_auc:.1%}") # честно показывает проблему
Вывод
ROC AUC НЕ зависит от дисбаланса классов. Это главное её преимущество. Она остаётся валидной метрикой качества моделей на дисбалансированных данных, когда Accuracy становится бесполезной. Однако при экстремно редких положительных примерах (<0.1%) стоит дополнять ROC AUC с Precision-Recall AUC или F1-score для полной картины.