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?

sapo_cosmico
источник

Ответы:

17

В документации 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: первый метод позволяет вам контролировать то, что используется для обучения и калибровки. Во втором методе используется перекрестная проверка, чтобы максимально эффективно использовать ваши данные для обеих целей.

Pintas
источник
12

Я также заинтересован в этом вопросе и хотел бы добавить несколько экспериментов, чтобы лучше понять 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 испытаний, каждый раз пробуя каждый метод и составляя его калибровочную кривую.

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

Бокплоты Бриера набирают очки во всех испытаниях:

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

Увеличение количества образцов до 10000:

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

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

Если мы изменим классификатор наивный Байес, возвращаясь к 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')

Таким образом, результаты оценки Бриера неубедительны, но в соответствии с кривыми лучше всего использовать второй метод.

Пользователь0
источник