Sklearn LogisticRegression и изменение порога по умолчанию для классификации

Я использую LogisticRegression из пакета sklearn и задаю быстрый вопрос о классификации. Я построил кривую ROC для моего классификатора, и оказалось, что оптимальный порог для моих данных обучения составляет около 0,25. Я предполагаю, что порог по умолчанию при создании прогнозов равен 0,5. Как я могу изменить эту настройку по умолчанию, чтобы узнать, какая точность в моей модели при выполнении 10-кратной перекрестной проверки? В принципе, я хочу, чтобы моя модель предсказала "1" для кого-то большего, чем 0,25, а не 0,5. Я просматривал всю документацию, и, похоже, я ничего не могу найти.

Заранее благодарим за помощь.

Ответ 1

Это не встроенная функция. Вы можете "добавить" его, обернув класс LogisticRegression в свой собственный класс и добавив атрибут threshold, который вы используете внутри пользовательского метода predict().

Однако некоторые предостережения:

  • Порог по умолчанию на самом деле равен 0. LogisticRegression.decision_function() возвращает знаковое расстояние до выбранной гиперплоскости разделения. Если вы смотрите predict_proba(), то вы смотрите на logit() расстояния по гиперплоскости с порогом 0,5. Но это дороже для вычисления.
  • Выбирая "оптимальный" порог, подобный этому, вы используете информационное пост-обучение, которое портит ваш тестовый набор (т.е. ваш тест или набор проверки больше не предоставляет объективную оценку ошибки вне выборки). Поэтому вы можете вызвать дополнительную переустановку, если только вы не выберете порог внутри цикла перекрестной проверки только на своем учебном наборе, а затем используйте его и обученный классификатор с вашим тестовым набором.
  • Рассмотрите возможность использования class_weight, если у вас есть неуравновешенная проблема, а не ручная установка порога. Это должно заставить классификатор выбрать гиперплоскость дальше от класса, представляющего серьезный интерес.

Ответ 2

Я хотел бы дать практический ответ

from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, confusion_matrix, recall_score, roc_auc_score, precision_score

X, y = make_classification(
    n_classes=2, class_sep=1.5, weights=[0.9, 0.1],
    n_features=20, n_samples=1000, random_state=10
)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)

clf = LogisticRegression(class_weight="balanced")
clf.fit(X_train, y_train)
THRESHOLD = 0.25
preds = np.where(clf.predict_proba(X_test)[:,1] > THRESHOLD, 1, 0)

pd.DataFrame(data=[accuracy_score(y_test, preds), recall_score(y_test, preds),
                   precision_score(y_test, preds), roc_auc_score(y_test, preds)], 
             index=["accuracy", "recall", "precision", "roc_auc_score"])

Изменяя THRESHOLD на 0.25, можно обнаружить, что показатели recall и precision снижаются. Однако при удалении аргумента class_weight accuracy возрастает, а показатель recall падает. Обратитесь к ответу @accepted

Ответ 3

Особый случай: одномерная логистическая регрессия

Значение, разделяющее регионы, где образец X помечен как 1 и где он помечен как 0, рассчитывается по формуле:

from scipy.special import logit
thresh = 0.1
val = (logit(thresh)-clf.intercept_)/clf.coef_[0]

Таким образом, прогнозы могут быть рассчитаны более непосредственно с

preds = np.where(X>val, 1, 0)

Ответ 4

Для полноты картины я хотел бы упомянуть еще один способ элегантного генерирования прогнозов, основанных на вычислениях вероятности скикита с использованием бинаризации:

import numpy as np
from sklearn.preprocessing import binarize

THRESHOLD = 0.25

# This probabilities would come from logistic_regression.predict_proba()
y_logistic_prob =  np.random.uniform(size=10)

predictions = binarize(y_logistic_prob.reshape(-1, 1), THRESHOLD).ravel()

Кроме того, я согласен с соображениями, которые Андреус высказывает, особенно 2 и 3. Обязательно следите за ними.