注意
转到最后下载完整示例代码,或通过 JupyterLite 或 Binder 在浏览器中运行此示例。
分类器校准比较#
校准良好的分类器是指概率分类器,其 predict_proba 的输出可以被直接解释为置信度。例如,一个校准良好的(二元)分类器应该对样本进行分类,使得对于它给出接近 0.8 的 predict_proba 值的样本,大约 80% 实际属于正类。
在本例中,我们将比较四种不同模型的校准:逻辑回归、高斯朴素贝叶斯、随机森林分类器和线性支持向量机。
# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause
数据集#
我们将使用一个包含 100,000 个样本和 20 个特征的合成二元分类数据集。在这 20 个特征中,只有 2 个具有信息量,2 个是冗余的(信息量特征的随机组合),其余 16 个是没有信息量的(随机数)。
在这 100,000 个样本中,将使用 100 个进行模型拟合,其余用于测试。请注意,这种拆分很不寻常:目标是为可能容易过拟合的模型获得稳定的校准曲线估计。在实践中,应该使用具有更平衡拆分的交叉验证,但这会使本示例的代码更难理解。
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
X, y = make_classification(
n_samples=100_000, n_features=20, n_informative=2, n_redundant=2, random_state=42
)
train_samples = 100 # Samples used for training the models
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
shuffle=False,
test_size=100_000 - train_samples,
)
校准曲线#
下面,我们使用小型训练数据集训练这四个模型中的每一个,然后使用测试数据集的预测概率绘制校准曲线(也称为可靠性图)。校准曲线是通过对预测概率进行分箱,然后绘制每个分箱中的平均预测概率与观察到的频率(“正类比例”)的关系来创建的。在校准曲线下方,我们绘制了一个直方图,显示了预测概率的分布,或者更具体地说,每个预测概率分箱中的样本数量。
import numpy as np
from sklearn.svm import LinearSVC
class NaivelyCalibratedLinearSVC(LinearSVC):
"""LinearSVC with `predict_proba` method that naively scales
`decision_function` output."""
def fit(self, X, y):
super().fit(X, y)
df = self.decision_function(X)
self.df_min_ = df.min()
self.df_max_ = df.max()
def predict_proba(self, X):
"""Min-max scale output of `decision_function` to [0,1]."""
df = self.decision_function(X)
calibrated_df = (df - self.df_min_) / (self.df_max_ - self.df_min_)
proba_pos_class = np.clip(calibrated_df, 0, 1)
proba_neg_class = 1 - proba_pos_class
proba = np.c_[proba_neg_class, proba_pos_class]
return proba
from sklearn.calibration import CalibrationDisplay
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegressionCV
from sklearn.naive_bayes import GaussianNB
# Define the classifiers to be compared in the study.
#
# Note that we use a variant of the logistic regression model that can
# automatically tune its regularization parameter.
#
# For a fair comparison, we should run a hyper-parameter search for all the
# classifiers but we don't do it here for the sake of keeping the example code
# concise and fast to execute.
lr = LogisticRegressionCV(
Cs=np.logspace(-6, 6, 101),
cv=10,
l1_ratios=(0,),
scoring="neg_log_loss",
max_iter=1_000,
use_legacy_attributes=False,
)
gnb = GaussianNB()
svc = NaivelyCalibratedLinearSVC(C=1.0)
rfc = RandomForestClassifier(random_state=42)
clf_list = [
(lr, "Logistic Regression"),
(gnb, "Naive Bayes"),
(svc, "SVC"),
(rfc, "Random forest"),
]
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
fig = plt.figure(figsize=(10, 10))
gs = GridSpec(4, 2)
colors = plt.get_cmap("Dark2")
ax_calibration_curve = fig.add_subplot(gs[:2, :2])
calibration_displays = {}
markers = ["^", "v", "s", "o"]
for i, (clf, name) in enumerate(clf_list):
clf.fit(X_train, y_train)
display = CalibrationDisplay.from_estimator(
clf,
X_test,
y_test,
n_bins=10,
name=name,
ax=ax_calibration_curve,
color=colors(i),
marker=markers[i],
)
calibration_displays[name] = display
ax_calibration_curve.grid()
ax_calibration_curve.set_title("Calibration plots")
# Add histogram
grid_positions = [(2, 0), (2, 1), (3, 0), (3, 1)]
for i, (_, name) in enumerate(clf_list):
row, col = grid_positions[i]
ax = fig.add_subplot(gs[row, col])
ax.hist(
calibration_displays[name].y_prob,
range=(0, 1),
bins=10,
label=name,
color=colors(i),
)
ax.set(title=name, xlabel="Mean predicted probability", ylabel="Count")
plt.tight_layout()
plt.show()

结果分析#
LogisticRegressionCV 尽管训练集规模较小,但仍返回了合理校准的预测:其可靠性曲线是四种模型中最接近对角线的。
逻辑回归是通过最小化对数损失来训练的,这是一个严格适当的评分规则:在无限训练数据的限制下,严格适当的评分规则被预测真实条件概率的模型最小化。因此,那个(假设的)模型将是完美校准的。然而,使用适当的评分规则作为训练目标本身并不足以保证模型校准良好:即使训练集非常大,如果逻辑回归被过度正则化,或者如果输入特征的选择和预处理使得这个模型被错误指定(例如,如果数据集的真实决策边界是输入特征的非线性函数),它仍然可能校准不佳。
在本例中,训练集故意保持非常小。在这种情况下,优化对数损失仍然可能因为过拟合而导致校准不佳的模型。为了减轻这种情况,LogisticRegressionCV 类被配置为通过内部交叉验证调整 C 正则化参数以最小化对数损失,从而在小型训练集设置中找到该模型的最佳折衷方案。
由于有限的训练集大小和缺乏良好指定的保证,我们观察到逻辑回归模型的校准曲线接近但并非完全在对角线上。该模型校准曲线的形状可以解释为略微不自信:与真实正样本比例相比,预测概率有点过于接近 0.5。
其他方法都输出校准较差的概率
GaussianNB在这个特定的数据集上倾向于将概率推向 0 或 1(参见直方图)(过度自信)。这主要是因为朴素贝叶斯方程仅在特征条件独立性的假设成立时才提供正确的概率估计 [2]。然而,特征可能相关,而这个数据集就是这种情况,它包含 2 个作为信息量特征的随机线性组合生成的特征。这些相关特征被有效地“计算了两次”,导致预测概率被推向 0 和 1 [3]。但请注意,更改用于生成数据集的种子可能会导致朴素贝叶斯估计器的结果差异很大。LinearSVC不是一个自然的概率分类器。为了将其预测解释为概率,我们天真地通过在上面定义的NaivelyCalibratedLinearSVC包装器类中应用 min-max 缩放,将 decision_function 的输出缩放到 [0, 1]。这个估计器在这个数据上显示出典型的 S 形校准曲线:大于 0.5 的预测对应于具有甚至更大的有效正类比例的样本(在对角线上方),而小于 0.5 的预测对应于甚至更低的正类比例(在对角线下方)。这种不自信的预测是最大边距方法的典型特征 [1]。RandomForestClassifier的预测直方图显示在约 0.2 和 0.9 概率处有峰值,而接近 0 或 1 的概率非常罕见。对此的解释由 [1] 给出:“诸如 bagging 和随机森林等平均基本模型预测的方法,可能难以做出接近 0 和 1 的预测,因为底层基本模型的方差会使本应接近零或一的预测偏离这些值。由于预测被限制在区间 [0, 1] 内,由方差引起的误差在接近零和一的地方往往是单侧的。例如,如果一个模型应该预测 p = 0,bagging 实现这一目标的唯一方法是所有 bagging 树都预测零。如果我们向 bagging 平均的树中添加噪声,这种噪声会导致一些树对这种情况预测大于 0 的值,从而使 bagging 集成的平均预测偏离 0。我们最强烈地观察到随机森林中的这种效应,因为通过随机森林训练的基本级别树由于特征子集化而具有相对较高的方差。”这种效应可以使随机森林不自信。尽管存在这种可能的偏差,请注意树本身是通过最小化 Gini 或 Entropy 准则来拟合的,这两个准则都导致最小化适当评分规则的分裂:分别是 Brier 分数或对数损失。有关更多详细信息,请参阅用户指南。这可以解释为什么该模型在这个特定示例数据集上显示出足够好的校准曲线。事实上,随机森林模型并不比逻辑回归模型明显更不自信。
您可以随意使用不同的随机种子和其他数据集生成参数重新运行此示例,以查看校准图的外观差异有多大。一般来说,逻辑回归和随机森林往往是校准最好的分类器,而 SVC 通常会显示典型的不自信的错误校准。朴素贝叶斯模型也经常校准不佳,但其校准曲线的总体形状可以根据数据集而变化很大。
最后,请注意,对于某些数据集种子,所有模型都校准不佳,即使像上面那样调整正则化参数也是如此。当训练规模太小或模型严重错误指定时,这种情况必然会发生。
参考文献#
脚本总运行时间: (0 minutes 2.760 seconds)
相关示例