Scikit cara yang benar untuk mengkalibrasi pengklasifikasi dengan CalibratedClassifierCV

14

Scikit memiliki CalibratedClassifierCV , yang memungkinkan kita untuk mengkalibrasi model kita pada pasangan X, y tertentu. Ini juga menyatakan dengan jelas itudata for fitting the classifier and for calibrating it must be disjoint.

Jika mereka harus dipisahkan, apakah sah untuk melatih pengklasifikasi dengan yang berikut?

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

Saya takut bahwa dengan menggunakan set latihan yang sama saya melanggar disjoint dataaturan. Alternatif mungkin memiliki set validasi

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

Yang memiliki kerugian meninggalkan sedikit data untuk pelatihan. Juga, jika CalibratedClassifierCV hanya harus sesuai pada model yang cocok pada set pelatihan yang berbeda, mengapa itu pilihan default cv=3, yang juga akan cocok dengan estimator basis? Apakah validasi silang menangani aturan disjoint sendiri?

Pertanyaan: apa cara yang benar untuk menggunakan CalibratedClassifierCV?

sapo_cosmico
sumber

Jawaban:

17

Ada dua hal yang disebutkan dalam dokumen CalibratedClassifierCV yang mengisyaratkan cara penggunaannya:

base_estimator: Jika cv = prefit, classifier pasti sudah sesuai pada data.

cv: Jika "prefit" disahkan, diasumsikan base_estimator sudah dipasang dan semua data digunakan untuk kalibrasi.

Saya mungkin jelas menafsirkan ini salah, tetapi tampaknya Anda dapat menggunakan CCCV (kependekan dari CalibratedClassifierCV) dengan dua cara:

Nomor satu:

  • Anda melatih model Anda seperti biasa your_model.fit(X_train, y_train),.
  • Kemudian, Anda membuat contoh CCCV Anda, your_cccv = CalibratedClassifierCV(your_model, cv='prefit'). Perhatikan Anda mengatur cvuntuk menandai bahwa model Anda sudah sesuai.
  • Akhirnya, Anda menelepon your_cccv.fit(X_validation, y_validation). Data validasi ini hanya digunakan untuk tujuan kalibrasi.

Nomor dua:

  • Anda memiliki model baru yang tidak terlatih .
  • Lalu kamu buat your_cccv=CalibratedClassifierCV(your_untrained_model, cv=3). Perhatikan cvsekarang jumlah lipatan.
  • Akhirnya, Anda menelepon your_cccv.fit(X, y). Karena model Anda tidak terlatih, X dan y harus digunakan untuk pelatihan dan kalibrasi. Cara untuk memastikan data 'disjoint' adalah validasi silang: untuk setiap lipatan yang diberikan, CCCV akan membagi X dan y menjadi data pelatihan dan kalibrasi Anda, sehingga tidak tumpang tindih.

TLDR: Metode satu memungkinkan Anda untuk mengontrol apa yang digunakan untuk pelatihan dan kalibrasi. Metode dua menggunakan validasi silang untuk mencoba dan memanfaatkan data Anda untuk kedua tujuan.

Pintas
sumber
12

Saya tertarik pada pertanyaan ini juga dan ingin menambahkan beberapa eksperimen untuk lebih memahami CalibratedClassifierCV (CCCV).

Seperti yang telah dikatakan, ada dua cara untuk menggunakannya.

#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)

Atau, kita bisa mencoba metode kedua tetapi hanya mengkalibrasi pada data yang sama dengan yang kita pasang.

#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)

Meskipun dokumen memperingatkan untuk menggunakan set terpisah, ini bisa berguna karena memungkinkan Anda untuk memeriksa my_clf(misalnya, untuk melihatcoef_ , yang tidak tersedia dari objek CalibratedClassifierCV). (Apakah ada yang tahu cara mendapatkan ini dari pengklasifikasi yang dikalibrasi --- untuk satu, ada tiga dari mereka sehingga Anda akan koefisien rata-rata?).

Saya memutuskan untuk membandingkan 3 metode ini dalam hal kalibrasi mereka pada set tes yang sepenuhnya diulurkan.

Berikut ini adalah dataset:

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

Saya melakukan beberapa ketidakseimbangan kelas dan hanya menyediakan 500 sampel untuk membuat ini masalah yang sulit.

Saya menjalankan 100 percobaan, setiap kali mencoba setiap metode dan merencanakan kurva kalibrasi.

masukkan deskripsi gambar di sini

Boxplots of the Brier skor atas semua percobaan:

masukkan deskripsi gambar di sini

Meningkatkan jumlah sampel menjadi 10.000:

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Jika kami mengubah classifier ke Naive Bayes, kembali ke 500 sampel:

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Tampaknya ini bukan sampel yang cukup untuk dikalibrasi. Meningkatkan sampel menjadi 10.000

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Kode lengkap

print(__doc__)

# Based on code by Alexandre Gramfort <[email protected]>
#         Jan Hendrik Metzen <[email protected]>

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')

Jadi, hasil skor Brier tidak meyakinkan, tetapi menurut kurva tampaknya lebih baik menggunakan metode kedua.

pengguna0
sumber