AdaBoost分类器完全图解

译者 | 朱先忠审校 | 重楼本文将通过完整的源码与图解方式向你展示AdaBoost算法运行逻辑,并指出其优点与不足,还将其与随机森林算法进行对比分析。 简介每个人都会犯错,即使是机器学习领域最简单的决策树也存在这个问题。 AdaBoost(自适应增强)算法不会忽略这些错误,而是会做一些不同的事情:它会从这些错误中学习(或适应)以变得更好。

AdaBoost分类器完全图解

译者 | 朱先忠

审校 | 重楼

本文将通过完整的源码与图解方式向你展示AdaBoost算法运行逻辑,并指出其优点与不足,还将其与随机森林算法进行对比分析。

简介

每个人都会犯错,即使是机器学习领域最简单的决策树也存在这个问题。AdaBoost(自适应增强)算法不会忽略这些错误,而是会做一些不同的事情:它会从这些错误中学习(或适应)以变得更好。

与一次生成多棵树的随机森林不同,AdaBoost算法从一棵简单的树开始,并识别它错误分类的实例。然后,它会构建新的树来修复这些错误,从错误中学习,并在每一步中变得更好。

在本文中,我们将详细探讨AdaBoost算法是如何进行预测的。我们将会看到AdaBoost算法能够通过结合有针对性的弱学习器来增强力量,就像将有针对性的锻炼变成全身力量的锻炼程序一样。

AdaBoost分类器完全图解

作者本人使用Canva Pro创建(针对移动设备进行了优化;在桌面PC上可能显得过大)。

定义

AdaBoost算法是一种集成机器学习模型,它能够创建一系列加权决策树,通常使用浅树(通常只是单层“树桩”)来实现。每棵树都在整个数据集上进行训练,但采用了自适应样本权重,使先前分类错误的样本更加重要。

对于分类任务,AdaBoost通过加权投票系统组合树,其中表现更好的树在最终决策中具有更大的影响力。

该模型的优势来自其自适应学习过程——虽然每棵简单的树可能都是“弱学习器”,其表现仅略优于随机猜测,但树的加权组合创造了一个“强学习器”,可以逐步关注和纠正错误。

AdaBoost分类器完全图解

AdaBoost是增强算法系列的一部分,因为它一次构建一棵树。每棵新树都会尝试修复先前树所犯的错误。然后,它使用加权投票来组合它们的答案并做出最终预测。

测试数据集

在本文中,我们将重点介绍经典高尔夫数据集作为分类的样本。

AdaBoost分类器完全图解

各列含义:“Outlook(展望)”——独热编码为3列、“Temperature(温度)”——华氏度、“Humidity(湿度)”——百分比、“Windy(有风)——(是/否)和“播放(Play)”——是/否,代表目标特征。

复制

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
# 创建和准备数据集
dataset_dict = {
    'Outlook': ['sunny', 'sunny', 'overcast', 'rainy', 'rainy', 'rainy', 'overcast', 
                'sunny', 'sunny', 'rainy', 'sunny', 'overcast', 'overcast', 'rainy',
                'sunny', 'overcast', 'rainy', 'sunny', 'sunny', 'rainy', 'overcast',
                'rainy', 'sunny', 'overcast', 'sunny', 'overcast', 'rainy', 'overcast'],
    'Temperature': [85.0, 80.0, 83.0, 70.0, 68.0, 65.0, 64.0, 72.0, 69.0, 75.0, 75.0,
                   72.0, 81.0, 71.0, 81.0, 74.0, 76.0, 78.0, 82.0, 67.0, 85.0, 73.0,
                   88.0, 77.0, 79.0, 80.0, 66.0, 84.0],
    'Humidity': [85.0, 90.0, 78.0, 96.0, 80.0, 70.0, 65.0, 95.0, 70.0, 80.0, 70.0,
                 90.0, 75.0, 80.0, 88.0, 92.0, 85.0, 75.0, 92.0, 90.0, 85.0, 88.0,
                 65.0, 70.0, 60.0, 95.0, 70.0, 78.0],
    'Wind': [False, True, False, False, False, True, True, False, False, False, True,
             True, False, True, True, False, False, True, False, True, True, False,
             True, False, False, True, False, False],
    'Play': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes', 'Yes',
             'Yes', 'Yes', 'No', 'No', 'Yes', 'Yes', 'No', 'No', 'No', 'Yes', 'Yes',
             'Yes', 'Yes', 'Yes', 'Yes', 'No', 'Yes']
}
# 准备数据
df = pd.DataFrame(dataset_dict)
df = pd.get_dummies(df, columns=['Outlook'], prefix='', prefix_sep='', dtype=int)
df['Wind'] = df['Wind'].astype(int)
df['Play'] = (df['Play'] == 'Yes').astype(int)

# 重新安排各列
column_order = ['sunny', 'overcast', 'rainy', 'Temperature', 'Humidity', 'Wind', 'Play']
df = df[column_order]

# 准备特征和目标
X,y = df.drop('Play', axis=1), df['Play']
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.5, shuffle=False)Main Mechanism

AdaBoost算法主要机制

AdaBoost算法的工作原理如下:

  • 初始化权重:为每个训练样本分配相同的权重。
  • 迭代学习:在每个步骤中,训练一个简单的决策树并检查其性能。错误分类的样本获得更多权重,使其成为下一棵树的优先级。正确分类的样本保持不变,所有权重都调整为总和为1。
  • 构建弱学习器:每个新的简单树都针对前几棵树的错误,创建一系列专门的弱学习器。
  • 最终预测:通过加权投票合并所有树,其中每棵树的投票都基于其重要性值,从而为更准确的树提供更大的影响力。

AdaBoost分类器完全图解

AdaBoost分类器使用许多简单的决策树(通常为50~100棵)进行预测。每棵树称为“树桩”,专注于一个重要特征,如温度或湿度。最终预测是通过合并所有树的投票做出的,每个投票都根据该树的重要性(“alpha”)加权。

训练步骤

在这里,我们将遵循SAMME(使用多类指数损失函数的分阶段加性建模)算法,这是scikit-learn库中处理二分类和多类分类的标准方法。

1.1.决定要使用的弱学习器。其中,单级决策树(或“树桩”)是默认选择。

1.2.决定要构建多少个弱学习器(在本例中为树的数量)(默认值为50棵树)。

AdaBoost分类器完全图解

我们从深度为1的决策树(树桩)开始作为弱学习器。每个树桩只进行一次分割,我们将按顺序训练其中的50个,并在此过程中调整权重。

1.3.开始时,为每个训练样本赋予相同的权重:

  • 每个样本的权重=1/N(N是样本总数)
  • 所有权重加起来为1

AdaBoost分类器完全图解

所有数据点的权重都相同(0.0714),总权重加起来为1。这确保在训练开始时每个样本都同等重要。

对于第一棵树

2.1.在考虑样本权重的同时构建决策树桩

AdaBoost分类器完全图解

在进行第一次分割之前,算法会检查所有数据点及其权重,以找到最佳分割点。这些权重会影响每个样本在进行分割决策时的重要性。

计算根节点的初始加权基尼不纯度

AdaBoost分类器完全图解

算法计算根节点的基尼不纯度分数,但现在考虑所有数据点的权重。

对于每个特征:

  • 按特征值对数据进行排序(与决策树分类器完全相同)

AdaBoost分类器完全图解

对于每个特征,算法都会对数据进行排序并识别潜在的分割点,与标准决策树完全相同。

对于每个可能的分割点:

  • 将样本分成左组和右组
  • 计算两个组的加权基尼不纯度
  • 计算此分割的加权基尼不纯度减少量

AdaBoost分类器完全图解

该算法计算每个潜在分割的加权基尼不纯度并将其与父节点进行比较。对于分割点为0.5的特征“sunny”,此不纯度减少量(0.066)显示了此分割对数据分离的改善程度。

选择提供最大基尼不纯度减少量的分割

AdaBoost分类器完全图解

在检查所有可能的分割特征后,“overcast”列(分割点为0.5)提供最高的不纯度减少量0.102。这意味着它是分离类别的最有效方法,使其成为第一次分割的最佳选择。

d. 使用此决策创建一个简单的单分割树

AdaBoost分类器完全图解

使用找到的最佳分割点,算法将数据分成两组,每组保留其原始权重。这个简单的决策树故意保持较小和不完美,使其略优于随机猜测。

2.2.评估这棵树有多好

a. 使用树预测训练集的标签。

b. 将所有错误分类的样本的权重相加以获得错误率。

AdaBoost分类器完全图解

第一个弱学习器对训练数据进行预测,我们检查它在哪里犯了错误(标记为X)。0.357的错误率表明这棵简单的树对一些预测有误,这是预料之中的,并将有助于指导接下来的训练步骤。

c. 使用以下方法计算树重要性(α):

α = learning_rate × log((1-error)/error)

AdaBoost分类器完全图解

我们使用错误率计算树的影响力得分(α = 0.5878)。分数越高意味着树越准确,这棵树因其良好的性能获得了中等重要性。

2.3.更新样本权重

a. 保留正确分类样本的原始权重。

b.将错误分类的样本的权重乘以e^(α)。

c. 将每个权重除以所有权重的总和。此归一化可确保所有权重的总和仍为1,同时保持其相对比例。

AdaBoost分类器完全图解

树出错的情况(标记为X)在下一轮中获得更高的权重。增加这些权重后,所有权重均被归一化为总和为1,确保错误分类的样本在下一棵树中得到更多关注。

对于第二棵树

2.1.构建新的树桩,但现在使用更新后的权重

a. 计算根节点的新加权基尼不纯度:

  • 将会有所不同,因为错误分类的样本现在具有更大的权重
  • 正确分类的样本现在具有更小的权重

AdaBoost分类器完全图解

使用更新后的权重(其中错误分类的样本现在具有更高的重要性),算法计算根节点的加权基尼不纯度。这开始了构建第二棵决策树的过程。

b. 对于每个特征:

  • 使用与之前相同的过程,但权重已更改。

c. 选择具有最佳加权基尼不纯度减少的分割。

  • 通常与第一棵树的分割完全不同。
  • 关注第一棵树错误的样本。

AdaBoost分类器完全图解

使用更新后的权重,不同的分割点显示出不同的有效性。请注意,“overcast(阴天)”不再是最佳分割——算法现在发现温度(84.0)可以最大程度地减少不纯度,从而显示权重变化如何影响分割选择。

d.创建第二个树桩。

AdaBoost分类器完全图解

使用温度≤84.0作为分割点,算法根据哪个类在该组中的总权重更大,而不是仅通过计算样本,为每个叶子分配YES/NO。这种加权投票有助于纠正前一棵树的错误。

2.2.评估这棵新树

a.用当前权重计算错误率。

b.使用与之前相同的公式计算其重要性(α)。

2.3.再次更新权重——相同的过程(增加错误权重,然后归一化)

AdaBoost分类器完全图解

第二棵树的错误率(0.222)和重要性得分(α=1.253)比第一棵树低。和以前一样,错误分类的样本在下一轮中获得更高的权重。

对于第三棵树及以后的所有剩余树

重复上述步骤2.1-2.3。

AdaBoost分类器完全图解

该算法按顺序构建50棵简单决策树,每棵都有自己的重要性得分(α)。每棵树通过关注数据的不同方面从以前的错误中学习,从而创建一个强大的组合模型。请注意,有些树(如树2)在表现更好时会获得更高的权重分数。

第3步:组合到一起

3.1.保留所有树及其重要性分数

AdaBoost分类器完全图解

50棵简单决策树作为一个团队一起工作,每棵都有自己的重要性分数(α)。在进行预测时,具有较高α值的树(如树2的1.253)对最终决策的影响比分数较低的树更大。

复制

from sklearn.tree import plot_tree
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt

#训练AdaBoost算法
np.random.seed(42)  # 可重复性
clf = AdaBoostClassifier(algorithm='SAMME', n_estimators=50, random_state=42)
clf.fit(X_train, y_train)

# 为树1、2和50创建可视化形式
trees_to_show = [0, 1, 49]
feature_names = X_train.columns.tolist()
class_names = ['No', 'Yes']

#设置绘图
fig, axes = plt.subplots(1, 3, figsize=(14,4), dpi=300)
fig.suptitle('Decision Stumps from AdaBoost', fontsize=16)

#绘制每棵树
for idx, tree_idx in enumerate(trees_to_show):
    plot_tree(clf.estimators_[tree_idx],
              feature_names=feature_names,
              class_names=class_names,
              filled=True,
              rounded=True,
              ax=axes[idx],
              fontsize=12)  #增加字体大小
    axes[idx].set_title(f'Tree {tree_idx + 1}', fontsize=12)

plt.tight_layout(rect=[0, 0.03, 1, 0.95])

AdaBoost分类器完全图解

每个节点将其“值”参数显示为[weight_NO, weight_YES],表示该节点上每个类型的加权比例。这些权重来自我们在训练期间计算的样本权重。

测试步骤

为了预测,需要:

  1. 获取每棵树的预测值。
  2. 将每个预测值乘以其权重得分(α)。
  3. 将它们全部加起来。
  4. 总权重较高的类型将是最终预测结果。

AdaBoost分类器完全图解

在预测新数据时,每棵树都会做出预测并将其乘以其权重得分(α)。最终决定来自将所有加权投票相加。在这里,NO类型获得更高的总分(23.315相对于15.440),因此模型预测这个未见过的样本为NO。

评估步骤

构建完所有树后,接下来,我们就可以进行测试集评估了。

AdaBoost分类器完全图解

通过迭代训练和加权弱学习器以关注错误分类的样本,AdaBoost创建了一个强大的分类器,可实现高精度——通常比单个决策树或更简单的模型更好!

复制

#获得预测结果
y_pred = clf.predict(X_test)

#使用实际值和预测值创建数据帧
results_df = pd.DataFrame({
    'Actual': y_test,
    'Predicted': y_pred
})
print(results_df) # 显示结果数据帧

# 计算和显示精度
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_test, y_pred)
print(f"\nModel Accuracy: {accuracy:.4f}")

关键参数解释

以下是AdaBoost算法的关键参数解释(特别是在scikit-learn库中提供的那些):

estimator(估计器)

这是AdaBoost用来构建最终解决方案的基本模型。三个最常见的弱学习器是:

  • 深度为1的决策树(决策树桩):这是默认且最受欢迎的选择。由于它只有一个分割,因此它被认为是一种非常弱的学习器,比随机猜测略好一点,这正是提升过程所需要的。
  • 逻辑回归:逻辑回归(尤其是高惩罚)也可以在这里使用,即使它并不是真正的弱学习器。它可能对具有线性关系的数据有用。
  • 深度较小的决策树(例如深度2或3):这些比决策树桩稍微复杂一些。它们仍然相当简单,但可以处理比决策树桩稍微复杂一些的模式。

AdaBoost分类器完全图解

AdaBoost的基础模型可以是简单的决策树桩(深度=1)、小型树(深度2-3)或惩罚线性模型。每种类型都保持简单以避免过度拟合,同时提供不同的方法来捕获模式。

n_estimators

要组合的弱学习器的数量,通常约为50-100;当这个值超过100时很少有更好的效果。

learning_rate

控制每个分类器对最终结果的影响程度。常见的起始值为0.1、0.5或1.0。较低的数字(如0.1)和稍高的n_estimator通常效果更好。

与随机森林算法的主要区别

由于随机森林和AdaBoost都适用于多棵树,因此很容易混淆所涉及的参数。关键区别在于随机森林独立组合多棵树(装袋),而AdaBoost一棵树接一棵树地构建树以修复错误(提升)。以下是关于它们之间的差异的其他一些细节:

  • 没有bootstrap参数,因为AdaBoost使用所有数据,但权重会发生变化
  • 没有oob_score参数,因为AdaBoost不使用bootstrap放回抽样
  • learning_rate变得至关重要(随机森林中不存在)
  • 与随机森林的较深树不同,树的深度通常保持得很浅(通常只是树桩)
  • 关键之处从并行独立树转移到顺序依赖树,这使得n_jobs等参数不那么重要

AdaBoost算法的优点与缺点

优点:

  • 自适应学习:AdaBoost通过赋予其所犯错误更多权重而变得更好。每棵新树都会更加关注它出错的困难情况。
  • 抵抗过度拟合:尽管它不断逐一添加更多树,但AdaBoost通常不会过于专注于训练数据。这是因为它使用加权投票,因此没有一棵树可以过多地控制最终答案。
  • 内置特征的选择:AdaBoost自然会找到最重要的特征。每棵简单树都会为该轮选择最有用的特征,这意味着它在训练时会自动选择重要特征。

缺点:

  • 对噪声敏感:由于它更重视错误,AdaBoost可能会在处理混乱或错误的数据时遇到麻烦。如果一些训练样本带有错误标签,它可能会过于关注这些不好的样本,从而使整个模型变得更糟。
  • 必须是连续的:与可以同时训练多棵树的随机森林不同,AdaBoost必须一次训练一棵树,因为每棵新树都需要知道之前的树的表现。这使得训练速度变慢。
  • 学习率敏感性:虽然它比随机森林需要调整的设置更少,但学习率确实会影响它的效果。如果学习率太高,它可能会过于精确地学习训练数据。如果学习率太低,它需要更多的树才能正常工作。

结语

AdaBoost是一种关键的增强算法,许多新方法都从中吸取了教训。它的主要思想——通过关注错误来变得更好——帮助塑造了许多现代机器学习工具。虽然其他方法都试图从一开始就做到完美,但AdaBoost却试图表明,有时解决问题的最佳方法是从错误中学习并不断改进。

AdaBoost在二元分类问题中以及数据干净时也最有效。虽然随机森林可能更适合更一般的任务(如预测数字)或混乱的数据,但AdaBoost在正确使用时可以产生非常好的结果。这么多年后人们仍在使用它,这一事实表明其核心思想有多好用!

AdaBoost分类器代码归纳

复制

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier

# 创建数据集
dataset_dict = {
    'Outlook': ['sunny', 'sunny', 'overcast', 'rainy', 'rainy', 'rainy', 'overcast', 
                'sunny', 'sunny', 'rainy', 'sunny', 'overcast', 'overcast', 'rainy',
                'sunny', 'overcast', 'rainy', 'sunny', 'sunny', 'rainy', 'overcast',
                'rainy', 'sunny', 'overcast', 'sunny', 'overcast', 'rainy', 'overcast'],
    'Temperature': [85.0, 80.0, 83.0, 70.0, 68.0, 65.0, 64.0, 72.0, 69.0, 75.0, 75.0,
                   72.0, 81.0, 71.0, 81.0, 74.0, 76.0, 78.0, 82.0, 67.0, 85.0, 73.0,
                   88.0, 77.0, 79.0, 80.0, 66.0, 84.0],
    'Humidity': [85.0, 90.0, 78.0, 96.0, 80.0, 70.0, 65.0, 95.0, 70.0, 80.0, 70.0,
                 90.0, 75.0, 80.0, 88.0, 92.0, 85.0, 75.0, 92.0, 90.0, 85.0, 88.0,
                 65.0, 70.0, 60.0, 95.0, 70.0, 78.0],
    'Wind': [False, True, False, False, False, True, True, False, False, False, True,
             True, False, True, True, False, False, True, False, True, True, False,
             True, False, False, True, False, False],
    'Play': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes', 'Yes',
             'Yes', 'Yes', 'No', 'No', 'Yes', 'Yes', 'No', 'No', 'No', 'Yes', 'Yes',
             'Yes', 'Yes', 'Yes', 'Yes', 'No', 'Yes']
}
df = pd.DataFrame(dataset_dict)

#准备数据
df = pd.get_dummies(df, columns=['Outlook'], prefix='', prefix_sep='', dtype=int)
df['Wind'] = df['Wind'].astype(int)
df['Play'] = (df['Play'] == 'Yes').astype(int)

#拆分特征和目标
X, y = df.drop('Play', axis=1), df['Play']
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.5, shuffle=False)

# 训练AdaBoost
ada = AdaBoostClassifier(
    estimator=DecisionTreeClassifier(max_depth=1), # 创建基本估计器(决策桩)
    n_estimators=50,        #典型情况下使用比随机森林算法更少的树
    learning_rate=1.0,      # 默认学习率
    algorithm='SAMME',      # 目前唯一可用的算法(将在未来的scikit-learn更新中删除)
    random_state=42
)
ada.fit(X_train, y_train)

#预测和评估
y_pred = ada.predict(X_test)
print(f"Accuracy: {accuracy_score(y_test, y_pred)}")

进一步阅读

有关AdaBoostClassifier及其在scikit-learn中的实现的详细说明,读者可以参考官方文档,其中提供了有关其用法和参数的全面信息。

本文编程技术环境

本文使用Python 3.7和 scikit-learn 1.6。虽然讨论的概念普遍适用,但具体代码实现可能会因版本不同而略有不同。

关于插图

除非另有说明,本文所有图像均由作者本人创建,并采用了Canva Pro的授权设计元素。

译者介绍

朱先忠,51CTO社区编辑,51CTO专家博客、讲师,潍坊一所高校计算机教师,自由编程界老兵一枚。

原文标题:AdaBoost Classifier, Explained: A Visual Guide with Code Examples,作者:Samy Baladram

给TA打赏
共{{data.count}}人
人已打赏
理论

ChatGPT付费功能免费用!Mistral把Canvas、Artifact全复制了

2024-11-20 7:00:00

理论

Qwen2.5更新百万超长上下文,推理速度4.3倍加速,网友:RAG要过时了

2024-11-20 9:36:00

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
搜索