多类别 AdaBoost 决策树#
此示例展示了 boosting 如何提高多标签分类问题的预测准确性。它再现了 Zhu 等人 [1] 图 1 中描述的类似实验。
AdaBoost(自适应增强)的核心原理是在重复重采样的数据版本上拟合一系列弱学习器(例如决策树)。每个样本都带有一个权重,该权重在每个训练步骤后进行调整,以便将更高的权重分配给分类错误的样本。带放回的重采样过程考虑了分配给每个样本的权重。权重较高的样本更有可能在新数据集中被多次选中,而权重较低的样本被选中的可能性较小。这确保了算法的后续迭代侧重于难以分类的样本。
参考文献
# Noel Dawe <[email protected]>
# License: 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
)
我们将数据集分为 2 组: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
。该估计器利用 boosting 来提高分类准确性。Boosting 是一种旨在训练从其前任错误中学习的弱学习器(即 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,
algorithm="SAMME",
random_state=42,
).fit(X_train, y_train)
分析#
AdaBoostClassifier
的收敛性#
为了证明 boosting 在提高准确性方面的有效性,我们评估了增强树的错误分类误差,并与两个基线分数进行了比较。第一个基线分数是从单个弱学习器(即 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
)在测试集上每次 boosting 迭代的 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()
该图显示了每次 boosting 迭代后测试集上的错误分类误差。我们看到,增强树的误差在 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()
在左图中,我们展示了每个弱学习器在每次 boosting 迭代中,在重新加权的训练集上的加权误差。在右图中,我们展示了与每个弱学习器相关的权重,这些权重稍后用于进行最终加性模型的预测。
我们看到,弱学习器的误差与权重成反比。这意味着我们的加性模型将通过增加其对最终决策的影响,更加信任在训练集上误差较小的弱学习器。事实上,这正是 AdaBoost 中每次迭代后更新基学习器权重的公式。
数学细节#
与在阶段 \(m\) 训练的弱学习器相关的权重与其误分类误差成反比,因此
其中 \(\alpha^{(m)}\) 和 \(err^{(m)}\) 分别是第 \(m\) 个弱学习器的权重和误差,\(K\) 是我们分类问题中的类别数。
另一个有趣的观察结果可以归结为:模型的第一个弱学习器比 boosting 链中后面的弱学习器产生的错误更少。
这种观察背后的直觉是:由于样本重新加权,后面的分类器被迫尝试对更困难或有噪声的样本进行分类,而忽略已经分类良好的样本。因此,训练集上的总体误差将会增加。这就是为什么弱学习器的权重是为了平衡表现较差的弱学习器而构建的。
脚本总运行时间:(0 分钟 4.966 秒)
相关示例