Scikit使用CalibratedClassifierCV校准分类器的正确方法


15

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的正确方法是什么?

Answers:


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:方法一允许您控制用于培训和校准的内容。方法二使用交叉验证来尝试并充分利用数据来达到这两个目的。


13

我也对此问题感兴趣,并希望添加一些实验以更好地了解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对象不可用的)。(有谁知道如何从校准的分类器中获得这一数据,因为其中一个是三个,所以您可以对系数求平均吗?)。

我决定在完全支持的测试集上比较这三种方法的校准。

这是一个数据集:

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 Boxboxts在所有试验中的得分:

在此处输入图片说明

将样本数量增加到10,000:

在此处输入图片说明

在此处输入图片说明

如果将分类器更改为朴素贝叶斯,则返回500个样本:

在此处输入图片说明

在此处输入图片说明

这似乎不足以校准样品。将样本增加到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')

因此,Brier得分结果尚无定论,但根据曲线,似乎最好使用第二种方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.