ScikitがCalibratedClassifierCVで分類子を調整する正しい方法


14

ScikitにはCalibratedClassifierCVがあり、これにより特定のX、yペアでモデルを調整できます。また、明確に述べていますdata for fitting the classifier and for calibrating it must be disjoint.

それらがばらばらでなければならない場合、分類器を次のもので訓練することは合法ですか?

model = CalibratedClassifierCV(my_classifier)
model.fit(X_train, y_train)

同じトレーニングセットを使用することで、disjoint data規則に違反しているのではないかと心配しています。別の方法として、検証セットを用意することもできます

my_classifier.fit(X_train, y_train)
model = CalibratedClassifierCV(my_classifier, cv='prefit')
model.fit(X_valid, y_valid)

これには、トレーニング用のデータが少なくなるという欠点があります。また、CalibratedClassifierCVが別のトレーニングセットに適合するモデルにのみ適合しなければならない場合、なぜデフォルトのオプションはでありcv=3、これも基本推定量に適合しますか?相互検証は、独立したルールを単独で処理しますか?

質問:CalibratedClassifierCVを使用する正しい方法は何ですか?

回答:


17

CalibratedClassifierCVドキュメントには、使用方法を示唆する 2つのことが記載されています。

base_estimator: cv = prefitの場合、分類子は既にデータに適合している必要があります。

cv:「prefit」が渡された場合、base_estimatorが既に適合しており、すべてのデータがキャリブレーションに使用されていると想定されます。

私は明らかにこれを間違って解釈しているかもしれませんが、CCCV(CalibratedClassifierCVの略)を2つの方法で使用できるようです。

一番:

  • 通常どおりモデルをトレーニングしますyour_model.fit(X_train, y_train)
  • 次に、CCCVインスタンスを作成しますyour_cccv = CalibratedClassifierCV(your_model, cv='prefit')cvモデルが既に適合していることを示すフラグを設定していることに注意してください。
  • 最後に、を呼び出しますyour_cccv.fit(X_validation, y_validation)。この検証データは、キャリブレーションのみに使用されます。

ナンバー2:

  • 新しい、トレーニングされていないモデルがあります。
  • 次に、作成しますyour_cccv=CalibratedClassifierCV(your_untrained_model, cv=3)cv折り畳みの数が通知されます。
  • 最後に、を呼び出しますyour_cccv.fit(X, y)。モデルはトレーニングされていないため、トレーニングとキャリブレーションの両方にXとyを使用する必要があります。データが「ばらばら」であることを確認する方法は相互検証です。任意のフォールドに対して、CCCVはXとyをトレーニングデータとキャリブレーションデータに分割し、重複しないようにします。

TLDR:方法1では、トレーニングとキャリブレーションに使用するものを制御できます。方法2は、クロス検証を使用して、両方の目的でデータを最大限に活用しようとします。


12

私もこの質問に興味があり、CalibratedClassifierCV(CCCV)をよりよく理解するためにいくつかの実験を追加したかったです。

既に述べたように、それを使用する2つの方法があります。

#Method 1, train classifier within CCCV
model = CalibratedClassifierCV(my_clf)
model.fit(X_train_val, y_train_val)

#Method 2, train classifier and then use CCCV on DISJOINT set
my_clf.fit(X_train, y_train)
model = CalibratedClassifierCV(my_clf, cv='prefit')
model.fit(X_val, y_val)

または、2番目の方法を試すこともできますが、当てはめたのと同じデータで調整するだけです。

#Method 2 Non disjoint, train classifier on set, then use CCCV on SAME set used for training
my_clf.fit(X_train_val, y_train_val)
model = CalibratedClassifierCV(my_clf, cv='prefit')
model.fit(X_train_val, y_train_val)

ドキュメントはばらばらのセットを使用するように警告しますが、これは検査できるので便利ですmy_clf(たとえば、coef_CalibratedClassifierCVオブジェクトからは利用できないを確認するため)。(キャリブレーションされた分類子からこれを取得する方法を知っている人はいますか?---そのうちの3つがあるので、係数を平均しますか?)

私は、これら3つの方法を、完全にテストされたテストセットでのキャリブレーションに関して比較することにしました。

データセットは次のとおりです。

X, y = datasets.make_classification(n_samples=500, n_features=200,
                                    n_informative=10, n_redundant=10,
                                    #random_state=42, 
                                    n_clusters_per_class=1, weights = [0.8,0.2])

クラスの不均衡をいくつか投げて、これを困難な問題にするために500サンプルしか提供しませんでした。

各メソッドを試行し、その検量線をプロットするたびに、100回の試行を実行します。

ここに画像の説明を入力してください

すべての試験でのBrierスコアの箱ひげ図:

ここに画像の説明を入力してください

サンプル数を10,000に増やす:

ここに画像の説明を入力してください

ここに画像の説明を入力してください

500のサンプルに戻って、分類子をNaive Bayesに変更した場合:

ここに画像の説明を入力してください

ここに画像の説明を入力してください

これは、較正するのに十分なサンプルではないようです。サンプルを10,000に増やす

ここに画像の説明を入力してください

ここに画像の説明を入力してください

完全なコード

print(__doc__)

# Based on code by Alexandre Gramfort <alexandre.gramfort@telecom-paristech.fr>
#         Jan Hendrik Metzen <jhm@informatik.uni-bremen.de>

import matplotlib.pyplot as plt

from sklearn import datasets
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import brier_score_loss
from sklearn.calibration import CalibratedClassifierCV, calibration_curve
from sklearn.model_selection import train_test_split


def plot_calibration_curve(clf, name, ax, X_test, y_test, title):

    y_pred = clf.predict(X_test)
    if hasattr(clf, "predict_proba"):
        prob_pos = clf.predict_proba(X_test)[:, 1]
    else:  # use decision function
        prob_pos = clf.decision_function(X_test)
        prob_pos = \
            (prob_pos - prob_pos.min()) / (prob_pos.max() - prob_pos.min())

    clf_score = brier_score_loss(y_test, prob_pos, pos_label=y.max())

    fraction_of_positives, mean_predicted_value = \
        calibration_curve(y_test, prob_pos, n_bins=10, normalize=False)

    ax.plot(mean_predicted_value, fraction_of_positives, "s-",
             label="%s (%1.3f)" % (name, clf_score), alpha=0.5, color='k', marker=None)

    ax.set_ylabel("Fraction of positives")
    ax.set_ylim([-0.05, 1.05])
    ax.set_title(title)

    ax.set_xlabel("Mean predicted value")

    plt.tight_layout()
    return clf_score

    fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, ncols=1, figsize=(6,12))

    ax1.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated",)
    ax2.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated")
    ax3.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated")

    scores = {'Method 1':[],'Method 2':[],'Method 3':[]}


fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, ncols=1, figsize=(6,12))

ax1.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated",)
ax2.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated")
ax3.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated")

scores = {'Method 1':[],'Method 2':[],'Method 3':[]}

for i in range(0,100):

    X, y = datasets.make_classification(n_samples=10000, n_features=200,
                                        n_informative=10, n_redundant=10,
                                        #random_state=42, 
                                        n_clusters_per_class=1, weights = [0.8,0.2])

    X_train_val, X_test, y_train_val, y_test = train_test_split(X, y, test_size=0.80,
                                                        #random_state=42
                                                               )

    X_train, X_val, y_train, y_val = train_test_split(X_train_val, y_train_val, test_size=0.80,
                                                      #random_state=42
                                                     )

    #my_clf = GaussianNB()
    my_clf = LogisticRegression()

    #Method 1, train classifier within CCCV
    model = CalibratedClassifierCV(my_clf)
    model.fit(X_train_val, y_train_val)
    r = plot_calibration_curve(model, "all_cal", ax1, X_test, y_test, "Method 1")
    scores['Method 1'].append(r)

    #Method 2, train classifier and then use CCCV on DISJOINT set
    my_clf.fit(X_train, y_train)
    model = CalibratedClassifierCV(my_clf, cv='prefit')
    model.fit(X_val, y_val)
    r = plot_calibration_curve(model, "all_cal", ax2, X_test, y_test, "Method 2")
    scores['Method 2'].append(r)

    #Method 3, train classifier on set, then use CCCV on SAME set used for training
    my_clf.fit(X_train_val, y_train_val)
    model = CalibratedClassifierCV(my_clf, cv='prefit')
    model.fit(X_train_val, y_train_val)
    r = plot_calibration_curve(model, "all_cal", ax3, X_test, y_test, "Method 2 non Dis")
    scores['Method 3'].append(r)

import pandas
b = pandas.DataFrame(scores).boxplot()
plt.suptitle('Brier score')

したがって、ブライアースコアの結果は決定的ではありませんが、曲線によると、2番目の方法を使用するのが最善のようです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.