web-dev-qa-db-ja.com

sklearn LogisticRegressionおよび分類のデフォルトしきい値の変更

SklearnパッケージのLogisticRegressionを使用していますが、分類について簡単な質問があります。分類器のROC曲線を作成しましたが、トレーニングデータの最適なしきい値は約0.25であることがわかりました。予測を作成するときのデフォルトのしきい値は0.5であると想定しています。このデフォルト設定を変更して、10分割の相互検証を行うときにモデルの精度を確認するにはどうすればよいですか?基本的に、モデルでは、0.5ではなく0.25を超えるすべてのユーザーに対して「1」を予測する必要があります。すべてのドキュメントを調べてきましたが、どこにも行けないようです。

よろしくお願いします。

14
Chetan Prabhu

これは組み込みの機能ではありません。 LogisticRegressionクラスを独自のクラスでラップし、カスタムpredict()メソッド内で使用するthreshold属性を追加することで、これを「追加」できます。

ただし、いくつかの注意点があります。

  1. デフォルトのしきい値は実際には0です。LogisticRegression.decision_function()は、選択された分離超平面までの符号付き距離を返します。 predict_proba()を表示している場合は、しきい値0.5の超平面距離のlogit()を表示しています。しかし、それは計算するのにより高価です。
  2. このような「最適な」しきい値を選択することで、学習後の情報が利用され、テストセットが台無しになります(つまり、テストまたは検証セットでは、サンプル外エラーの公平な推定が提供されなくなります)。したがって、トレーニングセットのみの交差検証ループ内のしきい値を選択しない限り、追加の過剰適合を引き起こしている可能性があり、それをテストセットで使用します。
  3. しきい値を手動で設定するのではなく、不均衡な問題がある場合は、class_weightの使用を検討してください。これにより、分類器は、重要なクラスからさらに離れた超平面を選択する必要があります。
7
Andreus

実用的な答えを出したいと思います

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"])

THRESHOLD0.25に変更すると、recallprecisionのスコアが減少していることがわかります。ただし、class_weight引数を削除すると、accuracyは増加しますが、recallスコアは低下します。 @accepted回答を参照してください

10
J. Doe
def find_best_threshold(threshould, fpr, tpr):
   t = threshould[np.argmax(tpr*(1-fpr))]
   # (tpr*(1-fpr)) will be maximum if your fpr is very low and tpr is very high
   print("the maximum value of tpr*(1-fpr)", max(tpr*(1-fpr)), "for threshold", np.round(t,3))
   return t

この関数は、最高の真陽性率と長所率を見つけたい場合に使用できます

0
Sujit Jena

特殊なケース:1次元ロジスティック回帰

サンプルX1とラベル付けされている領域と0がラベル付けされている領域を区切る値は、次の式を使用して計算されます。

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

したがって、予測はより直接的に計算できます

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

完全を期すために、scikitの確率計算に基づいて予測をエレガントに生成する別の方法を紹介します binarizeを使用

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に同意します。それらに注意してください。

0
Arturo