Правильний шлях Scikit для калібрування класифікаторів за допомогою CalibratedClassifierCV


16

У 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?

Відповіді:


18

У документах CalibratedClassifierCV згадуються дві речі, які натякають на шляхи його використання:

base_estimator: Якщо cv = prefit, класифікатор повинен бути вже встановлений на даних.

cv: Якщо "prefit" передано, передбачається, що base_estimator вже встановлений і всі дані використовуються для калібрування.

Я, очевидно, трактую це неправильно, але, здається, ви можете використовувати CCCV (короткий для CalibratedClassifierCV) двома способами:

Номер один:

  • Ви навчаєте свою модель , як зазвичай, your_model.fit(X_train, y_train).
  • Потім створюється екземпляр CCCV, your_cccv = CalibratedClassifierCV(your_model, cv='prefit'). Зверніть увагу, що ви встановили cvпрапор, що ваша модель вже підходить.
  • Нарешті, ви телефонуєте your_cccv.fit(X_validation, y_validation). Ці дані перевірки використовуються виключно для калібрування.

Номер другий:

  • У вас є нова, непідготовлена модель.
  • Тоді ви створюєте your_cccv=CalibratedClassifierCV(your_untrained_model, cv=3). Зверніть увагу cvна кількість складок.
  • Нарешті, ви телефонуєте your_cccv.fit(X, y). Оскільки ваша модель не підготовлена, X і y потрібно використовувати як для тренувань, так і для калібрування. Способом переконатися, що дані є "неперервними", є перехресне підтвердження: для будь-якої складеної частини, CCCV розділить X і y на дані вашої підготовки та калібрування, щоб вони не перетиналися.

TLDR: Перший спосіб дозволяє контролювати те, що використовується для тренувань та калібрування. У другому способі використовується перехресне підтвердження, щоб спробувати максимально використати ваші дані для обох цілей.


14

Мене це питання також цікавить і хотів додати кілька експериментів, щоб краще зрозуміти CalibratedClassifierCV (CCCV).

Як уже було сказано, є два способи його використання.

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

Крім того, ми можемо спробувати другий метод, але просто відкалібрувати ті самі дані, що і нам.

#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 методи з точки зору їх калібрування на повністю витриманому тестовому наборі.

Ось набір даних:

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» за всі випробування:

введіть тут опис зображення

Збільшення кількості зразків до 10000:

введіть тут опис зображення

введіть тут опис зображення

Якщо ми змінимо класифікатор на Naive Bayes, повернемось до 500 зразків:

введіть тут опис зображення

введіть тут опис зображення

Здається, це недостатньо зразків для калібрування. Збільшення зразків до 10000

введіть тут опис зображення

введіть тут опис зображення

Повний код

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

Отже, результати оцінки Brier є непереконливими, але, згідно з кривими, найкраще використовувати другий метод.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.