1. calibration:キャリブレーションとは

分類モデルを学習するとpredict_probaで確率予測を取得できます。

ただし、この取得できる確率予測がアルゴリズムによっては歪んでいて妥当ではないことがあります。

この歪みを矯正することがcalibrationと呼ばれています。

sklearnのドキュメントでもcalibrationについて説明されています。

scikit-learn.org

Probability calibration

また、確率予測が確率として妥当か確認するためにcalibration_curveがあります。

このドキュメントでは下記のようなことが述べられています。

  1. LogisticRegressionの確率予測は妥当

  2. naive_bayesの確率予測は妥当ではないのでcalibrationが必要

  3. LinearSVCの確率予測は妥当ではないのでcalibrationが必要

2. LogisticRegressionでもcalibration_curveが歪むことがある

まずは試しということでLogisticRegressionのcalibration_curveを試してみました。

データを変えて数パターンのcalibration_curveを描画したところcalibration_curveに大きな歪みが生じるケースがありました。

「LogisticRegressionだから問題ない」

とか

「LinearSVCだからcalibrationが必要だ」

のようにアルゴリズムで判断するのではなく確率として扱う場合にはcalibration_curveを確認しておくことが大事だと感じました。

3. 実際にcalibration_curveを描画する

実装はsklearnのドキュメント内のコードを参考にしました。

データ作成時のrandom_stateを可変に指定できる関数を別途作成しています。

random_stateを0〜5でデータを作成してそれぞれでcalibration_curveを描画します。

結果としてrandom_state=5の場合にcalibration_curveが大きく歪みました

3.1. 実装コード

実際のコードです。

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

def simulate_calibration_curve(
    random_state=42,
):
    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()
    results=clf.fit(X_train, y_train)
    y_pred=clf.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,
            mean_predicted_value=mean_predicted_value,
            fraction_of_positives=fraction_of_positives,
        )
    )
    return calibration_curve_data

random_states=range(6)
data_list = [
    simulate_calibration_curve(r)
    for r in random_states
]
data = pd.concat(data_list)

sns.relplot(
    data=data,
    x='mean_predicted_value',
    y='fraction_of_positives',
    col='random_state',
    col_wrap=1,
    kind='line',
    marker='o',
).savefig('line.jpg')

3.2. 描画されたcalibration_curve_data

実際のプロットです。

random_stateが0〜4までは対角線上にプロットされていますが、5の場合に対角線上から外れて歪んでいる状況が確認できます。

line.jpg

4. まとめ

LogisticRegressionのcalibration_curveを試してみました。

データによっては確率に歪みが生じることが確認できました。

モデルのアウトプットを確率として扱いたい場合には確率に歪みがないか、念の為calibration_curveを確認することが大事だと感じました。