LogisticRegressionの確率予測をCalibrateしてみる

method=sigmoidでは効果がないがmethod=isotonicなら効果がありそう

LogisticRegressionの確率予測の歪みにCalibrateの効果があるのか確認してみた

🕒 Last mod: 2021-09-06


1. LogisticRegressionの確率予測の歪み

LogisticRegressionの確率予測にも歪みが生じることがあることをこちらの記事で確認しました。

今回はこの歪みの補正を試してみます。

2. sklearn.calibration.CalibratedClassifierCV

確率予測の補正は下記で実現できます。

2.1. オプション:method

上記の関数のオプションにはmethodがあり、2種類から選択します。

  1. sigmoid

  2. isotonic

2.1.1. sigmoid

パラメトリック手法で補正します。

LogisticRegressionはそもそもsigmoid関数を使用しています。

ですのでsigmoidで補正しても効果が無いのではないかと考えています。

一般的にパラメトリック手法なのでデータ件数が少ない場合に有効なmethodだと思います。

2.1.2. isotonic

対して、isotonicはノンパラメトリック手法による補正です。

パラメトリック手法のLogisticRegressionとは異なる手法なので補正にも効果が期待できます

一般的にノンパラメトリック手法なのでデータの仮定によらず汎用的に使用できそうですが、データ件数が少ない場合には有効ではなさそうです。

3. 実装

実際に試してみます。

コードは基本的にはLogisticRegressionの確率予測の歪みを確認したものとほぼ同じものです。

コードの改修点は下記となります。

改修点
  1. 関数の中にCalibratedClassifierCVの処理を追加

  2. calibration_method引数と追加しmethodを指定できるよう改修

calibration_methodにsigmoidとisotonicを指定して補正後のcalibration_curveをプロットしています。

example.py
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.calibration import calibration_curve
from sklearn.calibration import CalibratedClassifierCV
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()

def simulate_calibration_curve(
    random_state=42,
    calibration_method='sigmoid',
):
    X, y = make_classification(
        n_samples=100000,
        n_features=20,
        n_informative=2,
        n_redundant=10,
        random_state=random_state,
    )
    (
        X_train,
        X_test,
        y_train,
        y_test
    ) = train_test_split(
        X,
        y,
        test_size=0.99,
        random_state=random_state,
    )
    clf=LogisticRegression()
    result=clf.fit(
        X_train,
        y_train
    )
    calib = CalibratedClassifierCV(
        clf,
        cv=2,
        method=calibration_method
    )
    result=calib.fit(X_train, y_train)
    y_pred=calib.predict_proba(X_test)[:, 1]
    (
        fraction_of_positives,
        mean_predicted_value
    ) = calibration_curve(
        y_test,
        y_pred,
        n_bins=10
    )
    calibration_curve_data=pd.DataFrame(
        dict(
            random_state=random_state,
            method=calibration_method,
            mean_predicted_value=mean_predicted_value,
            fraction_of_positives=fraction_of_positives,
        )
    )
    return calibration_curve_data
data_list = [
    simulate_calibration_curve(
        5,
        m,
    ) for m in [
        'sigmoid',
        'isotonic',
    ]
]
data = pd.concat(data_list)
sns.relplot(
    data=data,
    x='mean_predicted_value',
    y='fraction_of_positives',
    col='method',
    col_wrap=1,
    kind='line',
    marker='o',
).savefig('line.jpg')

4. プロット結果

実際のプロットです。

確率予測に歪みが大きかったrandom_state=5でデータを作成しています。

プロット結果
line.jpg

4.1. sigmoidによる補正結果

想定していたように全く補正効果は確認できません。

LogisticRegressionの予測結果をsigmoidで補正しても意味がなさそうです。

4.2. isotonic

こちらは若干補正の効果が確認でき、対角線上に折れ線が近づきました。

とは言え十分に補正されているとは言い切れない結果です。

5. まとめ

LogisticRegressionの確率予測の歪みを補正してみました。

LogisticRegressionの確率予測でもmethod=isotonicで補正することで効果が確認できました。

今回は以上です。