← Назад к вопросам

Как выбрать threshold для бинарной классификации?

2.3 Middle🔥 171 комментариев
#Машинное обучение#Метрики и оценка моделей

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как выбрать threshold для бинарной классификации?

Threshold - это критическое значение вероятности, при котором мы принимаем решение об отнесении объекта к положительному классу. По умолчанию используется 0.5, но это не всегда оптимально. Выбор threshold - ключевой шаг для балансировки метрик точности и полноты.

Основные метрики для выбора threshold

Precision и Recall определяют, как изменяется качество модели при разных значениях threshold:

from sklearn.metrics import precision_recall_curve, roc_curve, auc
import matplotlib.pyplot as plt
import numpy as np

# Получаем предсказания вероятностей
y_pred_proba = model.predict_proba(X_test)[:, 1]
y_true = y_test

# Вычисляем Precision и Recall для разных threshold
precision, recall, thresholds = precision_recall_curve(y_true, y_pred_proba)
roc_fpr, roc_tpr, roc_thresholds = roc_curve(y_true, y_pred_proba)

# Визуализируем кривые
plt.figure(figsize=(12, 4))

plt.subplot(1, 2, 1)
plt.plot(recall, precision, marker=".")
plt.xlabel("Recall")
plt.ylabel("Precision")
plt.title("Precision-Recall Curve")

plt.subplot(1, 2, 2)
plt.plot(roc_fpr, roc_tpr, label=f"AUC = {auc(roc_fpr, roc_tpr):.3f}")
plt.plot([0, 1], [0, 1], "k--")
plt.xlabel("FPR")
plt.ylabel("TPR")
plt.legend()
plt.title("ROC Curve")
plt.show()

Методы выбора оптимального threshold

1. F1-Score максимизация

Lучше всего использовать, когда классы примерно сбалансированы и нужен trade-off между Precision и Recall.

from sklearn.metrics import f1_score

f1_scores = []
for threshold in thresholds:
    y_pred = (y_pred_proba >= threshold).astype(int)
    f1_scores.append(f1_score(y_true, y_pred))

optimal_threshold = thresholds[np.argmax(f1_scores)]
print(f"Оптимальный threshold (F1): {optimal_threshold:.3f}")

2. ROC-AUC и Youden Index

Максимизирует (TPR - FPR), хороший выбор для сбалансированных задач.

youden_j = roc_tpr - roc_fpr
optimal_idx = np.argmax(youden_j)
optimal_threshold = roc_thresholds[optimal_idx]
print(f"Оптимальный threshold (Youden): {optimal_threshold:.3f}")

3. Матрица потерь (Cost Matrix)

Если ошибки имеют разную стоимость (False Positive vs False Negative), выбираем threshold, минимизирующий общие потери.

# Пример: FN дороже в 3 раза, чем FP
cost_fn = 3
cost_fp = 1

total_costs = []
for threshold in thresholds:
    y_pred = (y_pred_proba >= threshold).astype(int)
    tn = np.sum((y_pred == 0) & (y_true == 0))
    fp = np.sum((y_pred == 1) & (y_true == 0))
    fn = np.sum((y_pred == 0) & (y_true == 1))
    tp = np.sum((y_pred == 1) & (y_true == 1))
    
    cost = cost_fp * fp + cost_fn * fn
    total_costs.append(cost)

optimal_threshold = thresholds[np.argmin(total_costs)]
print(f"Оптимальный threshold (Cost Matrix): {optimal_threshold:.3f}")

Практический выбор threshold

Для несбалансированных данных (например, fraud detection): выбирайте threshold, который максимизирует Recall для редкого класса при приемлемом Precision.

# Выбираем threshold с Recall >= 0.9 и максимальным Precision
min_recall = 0.9
for precision_val, recall_val, threshold in zip(precision, recall, thresholds):
    if recall_val >= min_recall:
        print(f"Threshold: {threshold:.3f}, Precision: {precision_val:.3f}, Recall: {recall_val:.3f}")
        break

Рекомендации

  • Всегда анализируйте бизнес-требования: что важнее - поймать все положительные (Recall) или быть уверенным в предсказании (Precision)?
  • Используйте cross-validation для выбора threshold на отдельной валидационной выборке, не на test.
  • Помните о дисбалансе классов: для редких классов (fraud, болезни) нужен более низкий threshold.
  • Мониторьте дрейф распределения: threshold может стать неоптимальным со временем в production.

Выбор threshold - это балансировка между потерями типа I и II ошибок с учетом бизнес-контекста задачи.

Как выбрать threshold для бинарной классификации? | PrepBro