注意
转到末尾以下载完整示例代码,或通过JupyterLite或Binder在浏览器中运行此示例。
多类别AdaBoost决策树#
此示例展示了增强(boosting)如何提高多标签分类问题的预测准确性。它重现了Zhu et al [1] 中图1所示的类似实验。
AdaBoost(自适应增强)的核心原理是在重复重采样的数据版本上拟合一系列弱学习器(例如决策树)。每个样本都带有一个权重,该权重在每次训练步骤后都会进行调整,以便将更高的权重分配给被错误分类的样本。带替换的重采样过程会考虑分配给每个样本的权重。权重较高的样本在新数据集中被多次选中的机会更大,而权重较低的样本被选中的可能性较小。这确保了算法的后续迭代将重点放在难以分类的样本上。
References
# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause
创建数据集#
通过采用十维标准正态分布(\(x\) in \(R^{10}\))构建分类数据集,并定义由嵌套同心十维球体分隔的三个类别,使得每个类别中的样本数量大致相等(\(\chi^2\)分布的分位数)。
from sklearn.datasets import make_gaussian_quantiles
X, y = make_gaussian_quantiles(
n_samples=2_000, n_features=10, n_classes=3, random_state=1
)
我们将数据集分成两组:70%的样本用于训练,其余30%用于测试。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y, train_size=0.7, random_state=42
)
训练 AdaBoostClassifier#
我们训练 AdaBoostClassifier。该估计器利用增强来提高分类准确性。增强是一种旨在训练从其前辈错误中学习的弱学习器(即 estimator)的方法。
在这里,我们将弱学习器定义为 DecisionTreeClassifier,并将最大叶节点数设置为8。在实际应用中,应调整此参数。我们将其设置为一个较低的值以限制示例的运行时间。
AdaBoostClassifier 中内置的 SAMME 算法随后使用当前弱学习器做出的正确或不正确预测来更新用于训练后续弱学习器的样本权重。此外,弱学习器本身的权重是根据其在分类训练样本时的准确性计算的。弱学习器的权重决定了它对最终集成预测的影响。
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
weak_learner = DecisionTreeClassifier(max_leaf_nodes=8)
n_estimators = 300
adaboost_clf = AdaBoostClassifier(
estimator=weak_learner,
n_estimators=n_estimators,
random_state=42,
).fit(X_train, y_train)
分析#
AdaBoostClassifier 的收敛性#
为了证明增强在提高准确性方面的有效性,我们评估了增强树的错误分类误差,并将其与两个基线分数进行比较。第一个基线分数是来自单个弱学习器(即 DecisionTreeClassifier)的 misclassification_error,它作为参考点。第二个基线分数来自 DummyClassifier,它预测数据集中最常见的类别。
from sklearn.dummy import DummyClassifier
from sklearn.metrics import accuracy_score
dummy_clf = DummyClassifier()
def misclassification_error(y_true, y_pred):
return 1 - accuracy_score(y_true, y_pred)
weak_learners_misclassification_error = misclassification_error(
y_test, weak_learner.fit(X_train, y_train).predict(X_test)
)
dummy_classifiers_misclassification_error = misclassification_error(
y_test, dummy_clf.fit(X_train, y_train).predict(X_test)
)
print(
"DecisionTreeClassifier's misclassification_error: "
f"{weak_learners_misclassification_error:.3f}"
)
print(
"DummyClassifier's misclassification_error: "
f"{dummy_classifiers_misclassification_error:.3f}"
)
DecisionTreeClassifier's misclassification_error: 0.475
DummyClassifier's misclassification_error: 0.692
在训练 DecisionTreeClassifier 模型之后,所达到的误差超过了通过猜测最常见类别标签(如 DummyClassifier 所做)所能获得的预期值。
现在,我们计算附加模型(DecisionTreeClassifier)在测试集上每次增强迭代的 misclassification_error,即 1 - accuracy,以评估其性能。
我们使用 staged_predict 进行迭代,迭代次数与拟合的估计器数量相同(即对应于 n_estimators)。在迭代 n 时,AdaBoost的预测仅使用前 n 个弱学习器。我们将这些预测与真实预测 y_test 进行比较,从而得出添加新弱学习器到链中是否有益的结论。
我们绘制不同阶段的错误分类误差
import matplotlib.pyplot as plt
import pandas as pd
boosting_errors = pd.DataFrame(
{
"Number of trees": range(1, n_estimators + 1),
"AdaBoost": [
misclassification_error(y_test, y_pred)
for y_pred in adaboost_clf.staged_predict(X_test)
],
}
).set_index("Number of trees")
ax = boosting_errors.plot()
ax.set_ylabel("Misclassification error on test set")
ax.set_title("Convergence of AdaBoost algorithm")
plt.plot(
[boosting_errors.index.min(), boosting_errors.index.max()],
[weak_learners_misclassification_error, weak_learners_misclassification_error],
color="tab:orange",
linestyle="dashed",
)
plt.plot(
[boosting_errors.index.min(), boosting_errors.index.max()],
[
dummy_classifiers_misclassification_error,
dummy_classifiers_misclassification_error,
],
color="c",
linestyle="dotted",
)
plt.legend(["AdaBoost", "DecisionTreeClassifier", "DummyClassifier"], loc=1)
plt.show()

该图显示了每次增强迭代后测试集上的错误分类误差。我们看到,增强树的误差在50次迭代后收敛到0.3左右,这表明与单个树相比,准确性显著更高,如图中虚线所示。
错误分类误差出现抖动是因为 SAMME 算法使用弱学习器的离散输出来训练增强模型。
AdaBoostClassifier 的收敛主要受学习率(即 learning_rate)、使用的弱学习器数量(n_estimators)以及弱学习器的表达能力(例如 max_leaf_nodes)的影响。
弱学习器的误差和权重#
如前所述,AdaBoost是一个前向分步附加模型。我们现在重点了解弱学习器的归因权重与其统计性能之间的关系。
我们使用拟合的 AdaBoostClassifier 属性 estimator_errors_ 和 estimator_weights_ 来调查这种联系。
weak_learners_info = pd.DataFrame(
{
"Number of trees": range(1, n_estimators + 1),
"Errors": adaboost_clf.estimator_errors_,
"Weights": adaboost_clf.estimator_weights_,
}
).set_index("Number of trees")
axs = weak_learners_info.plot(
subplots=True, layout=(1, 2), figsize=(10, 4), legend=False, color="tab:blue"
)
axs[0, 0].set_ylabel("Train error")
axs[0, 0].set_title("Weak learner's training error")
axs[0, 1].set_ylabel("Weight")
axs[0, 1].set_title("Weak learner's weight")
fig = axs[0, 0].get_figure()
fig.suptitle("Weak learner's errors and weights for the AdaBoostClassifier")
fig.tight_layout()

在左侧图中,我们显示了每次增强迭代时重加权训练集上每个弱学习器的加权误差。在右侧图中,我们显示了与每个弱学习器相关的权重,这些权重稍后用于做出最终附加模型的预测。
我们看到弱学习器的误差与权重成反比。这意味着我们的附加模型将通过增加其对最终决策的影响,更信任犯下更小错误(在训练集上)的弱学习器。事实上,这正是AdaBoost中每次迭代后更新基本估计器权重的公式。
数学细节#
在阶段 \(m\) 训练的弱学习器相关的权重与其错误分类误差成反比,使得
其中 \(\alpha^{(m)}\) 和 \(err^{(m)}\) 分别是第 \(m\) 个弱学习器的权重和误差,\(K\) 是我们分类问题中的类别数。
另一个有趣的观察结果是,模型中靠前的弱学习器比增强链中靠后的弱学习器犯的错误更少。
这一观察结果背后的直觉是:由于样本重加权,后面的分类器被迫尝试对更困难或噪声更大的样本进行分类,而忽略已经分类良好的样本。因此,训练集上的总体误差会增加。这就是为什么构建弱学习器的权重来抵消表现较差的弱学习器的影响。
脚本总运行时间: (0 minutes 3.299 seconds)
相关示例