Boosting算法-AdaBoost
一、AdaBoost概述
AdaBoost(Adaptive Boosting,自适应提升)是一种迭代的集成学习算法,通过组合多个弱分类器来构建强分类器。其核心思想是关注错误样本,通过不断调整样本权重,让后续的弱分类器更专注于那些之前被分错的样本,逐步改进模型的性能。它已被广泛应用于人脸表情识别、图像检索等领域。
二、AdaBoost基本思想
-
样本权重调整:在训练过程中,提高被弱分类器错分样本的权值,降低被正确分类样本的权值。这样一来,那些没有得到正确分类的数据,由于其权值加大而受到后一轮的弱分类器的更大关注,从而实现分类问题被一系列弱分类器“分而治之”。
-
弱分类器组合:采取加权多数表决的方法,误差率小的分类器的权值大,使其在表决过程中起较大作用。

三、AdaBoost算法流程

(一)初始化阶段
给定训练集,其中
。初始化样本权重:
即所有样本等权重。
(二)迭代训练(for t = 1 to T)
-
训练弱分类器:使用当前权重分布w^{(t)}训练弱分类器h_t(x),计算加权错误率:
其中I为指示函数,当时,
,否则为
。
-
计算分类器权重:
-
确定该弱分类器的权重:
-
当
时,
,且错误率越低,权重越大。
-
-
更新样本权重:增加错分样本权重,减少正确分类样本权重,更新公式为:
-
其中Z_t为归一化因子,用于确保
,计算公式:

-
对于错分样本:
,权重增大
-
对于正确样本:
,权重减小
-
(三)最终强分类器
最终的强分类器为
即根据所有弱分类器的加权和进行符号判断来确定样本的类别。
(四)算法分类器停止迭代的标志
1. 达到预设的最大迭代次数(最常用)
这是工程实现中最普遍的停止方式,对应参数为n_estimators(如 sklearn 的AdaBoostClassifier中默认值为 50)。
-
逻辑:预先设定弱分类器的总数量T,当迭代轮次t达到T时,停止训练新的弱分类器,权重调整自然结束;
-
示例:若设sT=100,则算法会训练 100 个弱分类器,计算 100 个
(t=1到 100),之后不再调整权重;
-
原因:简单易实现,且能通过交叉验证(如 GridSearchCV)优化T,平衡 “泛化能力” 与 “过拟合风险”(T过大会导致过拟合,过小则强分类器性能不足)。
2. 训练误差达到预设阈值(理论可行,实际少用)
若预设 “训练误差阈值”,当强分类器的训练误差(对所有训练样本的分类错误率)降至
以下时,停止迭代。
-
逻辑:强分类器的训练误差随迭代次数增加而下降(理论上呈指数级下降),若误差已满足需求(如
),则无需继续训练新弱分类器,权重调整停止;
-
局限性:实际数据中,训练误差可能在早期快速下降后进入 “平台期”,难以精确降至预设阈值;且过度追求低训练误差易导致过拟合,因此该方式较少单独使用。
3. 弱分类器错误率无法降低(特殊停止条件)
若某一轮迭代中,所有候选弱分类器的最小错误率(即弱分类器性能差于随机猜测),则停止迭代。
-
逻辑:根据\alpha_t的计算公式,若
,则
,
,导致
负的分类器权重会让该弱分类器在 “强分类器投票” 中起反作用,反而降低整体性能;
-
实际意义:此时数据可能存在 “线性不可分” 或 “噪声过多” 的问题,继续迭代无法提升性能,因此停止权重调整。
四、弱分类器的选择
在AdaBoost算法的第(t=n)轮(任意迭代轮次)中,弱分类器的选择逻辑与(t=1)轮核心原则一致,但需结合当前轮次的样本权重分布进行调整。具体来说:
(一)t=n轮选择弱分类器的核心原则
在第(t=n)轮,选择弱分类器的标准是:在当前样本权重分布下,找到“加权错误率最低”的弱分类器。
-
这里的“加权错误率”不再是简单的“错误样本数/总样本数”,而是错误分类样本的权重之和:
其中
是指示函数(分类错误时为1,正确时为0),
是第(n)轮的样本权重。
(二)与t=1轮的区别与联系
|
轮次 |
样本权重特点 |
错误率计算方式 |
选择逻辑 |
|
(t=1) |
所有样本权重相等w_i=1/N |
错误率 = 错误样本数 / 总样本数 |
找普通错误率最低的弱分类器 |
|
(t=n)((n>1)) |
样本权重不等(错分样本权重更高) |
加权错误率 = 错分样本权重之和 |
找加权错误率最低的弱分类器 |
(三)关键逻辑总结
-
权重引导学习:第(t=n)轮的样本权重是前(n-1)轮迭代的结果,错分样本的权重被放大,迫使算法优先关注这些“难分样本”。
-
动态最优选择:每一轮的最优弱分类器可能不同,因为样本权重分布在变化(例如(t=1)轮关注整体分类,(t=2)轮可能更关注某个错分样本)。
-
核心目标不变:始终选择“当前权重分布下加权错误率最低”的弱分类器,确保每一轮迭代都能最大程度降低分类误差。
这种机制使AdaBoost能“自适应”地聚焦于难分样本,逐步提升强分类器的性能。
四、AdaBoost的关键特性
-
自适应原理:通过调整样本分布,使后续分类器聚焦于难样本,例如在图像识别中难以分类的特定角度物体。
-
权重机制:样本权重反映了样本的分类难度,分类器权重反映了分类器的分类能力,误差率小的分类器权重更大。
-
误差上界:训练误差满足
,随着迭代进行,误差指数下降。
五、优缺点分析
|
维度 |
优点 |
缺点 |
|
模型特性 |
简单易实现,参数少 |
对异常值敏感,依赖弱分类器质量 |
|
泛化能力 |
误差指数下降,不易过拟合(合理迭代) |
迭代过多易过拟合,难分样本与异常值混淆 |
|
训练效率 |
无复杂运算,速度快,资源消耗低 |
弱分类器需顺序迭代,并行化受限 |
|
适用场景 |
二分类、小样本、低维度数据 |
多分类、回归、高噪声数据表现差 |
-
适用场景优先选择 AdaBoost:
-
数据量小(样本数 < 10 万)、维度低(特征数 < 1000),且标注质量高(无明显异常值);
-
追求 “快节奏实验”(需快速验证想法,无需复杂调参);
-
硬件资源有限(无 GPU,需 CPU 高效训练)。
-
-
不建议选择 AdaBoost:
-
数据含大量噪声或标注错误(如医疗数据中的标注偏差);
-
高维度、大样本数据(如深度学习中的图像像素特征);
-
多分类 / 回归任务(优先选 XGBoost、LightGBM);
-
非监督学习任务(如聚类、异常检测)。
-
六、Python代码案例
import numpy as np
# 定义样本数据和标签
# 蓝色样本(blue)标签设为1,红色样本(red)标签设为-1
blue = np.array([[-27, 38], [5, 34], [32, 3], [42, 10]])
red = np.array([[22, 38], [-5, -33], [-22, -25], [-37, -31]])
# 合并所有样本和标签
X = np.vstack((blue, red)) # 8个样本,每个样本2个特征(u, v)
y = np.hstack((np.ones(4), -np.ones(4))) # 标签:前4个为1(blue),后4个为-1(red)
n_samples = X.shape[0] # 总样本数:8
# 初始化样本权重 (t=1)
weights = np.ones(n_samples) / n_samples # 初始权重均为1/8
print("===== 初始状态 (t=1 前) =====")
print(f"所有样本初始权重: {weights.round(4)}")
print(f"权重总和: {sum(weights):.4f}") # 验证权重和为1
print()
# 定义函数:找到最优的平行轴弱分类器
def find_best_weak_classifier(X, y, weights):
best_error = float('inf')
best_h = None
best_feature = None
best_threshold = None
# 尝试所有可能的平行轴分类器(u轴和v轴)
# 1. 沿u轴分割 (特征0)
for i in range(X.shape[0]):
threshold = X[i, 0] # 以每个样本的u值为阈值
# 预测:u > threshold 为1,否则为-1
h = np.where(X[:, 0] > threshold, 1, -1)
error = np.sum(weights * (h != y)) # 加权错误率
if error < best_error:
best_error = error
best_h = h
best_feature = 0 # 0表示u轴
best_threshold = threshold
# 2. 沿v轴分割 (特征1)
for i in range(X.shape[0]):
threshold = X[i, 1] # 以每个样本的v值为阈值
# 预测:v > threshold 为1,否则为-1
h = np.where(X[:, 1] > threshold, 1, -1)
error = np.sum(weights * (h != y)) # 加权错误率
if error < best_error:
best_error = error
best_h = h
best_feature = 1 # 1表示v轴
best_threshold = threshold
return best_h, best_error, best_feature, best_threshold
# 执行2次迭代
for t in range(1, 3): # t=1和t=2
print(f"===== 第{t}次迭代 =====")
# 1. 找到当前最优弱分类器
h, error, feature, threshold = find_best_weak_classifier(X, y, weights)
feature_name = 'u' if feature == 0 else 'v'
# 2. 计算分类器权重alpha
alpha = 0.5 * np.log((1 - error) / error) if error != 0 else 100 # 避免除零
# 3. 计算归一化因子Z
Z = np.sum(weights * np.exp(-alpha * y * h))
# 4. 输出当前迭代信息
print(f"最优弱分类器: 沿{feature_name}轴,阈值={threshold}")
print(f"弱分类器预测结果: {h}")
print(f"加权错误率(ε{t}): {error:.4f}")
print(f"分类器权重(α{t}): {alpha:.4f}")
print(f"归一化因子(Z{t}): {Z:.4f}")
print(f"第{t}次迭代后样本权重: {weights.round(4)}")
# 5. 更新样本权重(为下一次迭代做准备)
if t < 2: # 第2次迭代后不需要更新
weights = (weights * np.exp(-alpha * y * h)) / Z
print()
# 输出最终的强分类器信息
print("===== 最终强分类器 =====")
print("强分类器 = sign(α1*h1 + α2*h2)")
七、sklearn中的AdaBoost
在scikit - learn中,提供了AdaBoostClassifier和AdaBoostRegressor分别用于分类和回归任务。
from sklearn.ensemble import AdaBoostClassifier#分类(离散型
from sklearn.ensemble import AdaBoostRegressor#回归(连续型
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import classification_report, accuracy_score
# 1. 准备数据
# 蓝色样本(blue)标签设为1,红色样本(red)标签设为0
blue = np.array([[-27, 38], [5, 34], [32, 3], [42, 10]])
red = np.array([[22, 38], [-5, -33], [-22, -25], [-37, -31]])
# 合并样本和标签
X = np.vstack((blue, red)) # 特征矩阵:8个样本,2个特征(u, v)
y = np.hstack((np.ones(4), np.zeros(4))) # 标签:蓝色为1,红色为0
sample_names = [f"blue{i+1}" for i in range(4)] + [f"red{i+1}" for i in range(4)]
# 2. 创建并训练AdaBoost模型
# 基础弱分类器使用深度为1的决策树(决策树桩)
base_estimator = DecisionTreeClassifier(max_depth=1)
# 创建AdaBoost分类器,迭代次数设为2
adaboost = AdaBoostClassifier(
estimator=base_estimator, # 使用estimator参数
n_estimators=2, # 迭代次数
learning_rate=1.0,
algorithm='SAMME' # 适合离散型弱分类器
)
# 3. 手动跟踪样本权重变化
print("===== 样本权重变化 =====")
# 初始权重
sample_weights = np.ones(len(X)) / len(X)
print(f"初始样本权重 (t=0):")
for name, weight in zip(sample_names, sample_weights):
print(f" {name}: {weight:.4f}")
print(f" 权重总和: {np.sum(sample_weights):.4f}\n")
# 训练并跟踪权重
adaboost.fit(X, y, sample_weight=sample_weights)
# 计算第一次迭代后的权重
estimator1 = adaboost.estimators_[0]
alpha1 = adaboost.estimator_weights_[0]
y_pred1 = estimator1.predict(X)
error1 = np.sum(sample_weights * (y_pred1 != y)) / np.sum(sample_weights)
# 更新权重
sample_weights *= np.exp(-alpha1 * (2 * (y_pred1 == y) - 1)) # 转换为+1/-1的形式计算
sample_weights /= np.sum(sample_weights) # 归一化
print(f"第一次迭代后样本权重 (t=1):")
for name, weight in zip(sample_names, sample_weights):
print(f" {name}: {weight:.4f}")
print(f" 权重总和: {np.sum(sample_weights):.4f}\n")
# 计算第二次迭代后的权重
estimator2 = adaboost.estimators_[1]
alpha2 = adaboost.estimator_weights_[1]
y_pred2 = estimator2.predict(X)
error2 = np.sum(sample_weights * (y_pred2 != y)) / np.sum(sample_weights)
# 更新权重
sample_weights *= np.exp(-alpha2 * (2 * (y_pred2 == y) - 1))
sample_weights /= np.sum(sample_weights) # 归一化
print(f"第二次迭代后样本权重 (t=2):")
for name, weight in zip(sample_names, sample_weights):
print(f" {name}: {weight:.4f}")
print(f" 权重总和: {np.sum(sample_weights):.4f}\n")
# 4. 模型预测与评估
y_pred = adaboost.predict(X)
# 输出评估结果
print("===== 模型评估 =====")
print(f"准确率: {accuracy_score(y, y_pred):.4f}")
print("\n分类报告:")
print(classification_report(y, y_pred, target_names=['红色', '蓝色']))
# 5. 输出弱分类器信息
print("\n===== 弱分类器信息 =====")
for i, estimator in enumerate(adaboost.estimators_):
# 弱分类器权重
print(f"\n弱分类器 {i+1} 权重: {adaboost.estimator_weights_[i]:.4f}")
# 弱分类器的决策阈值(针对决策树桩)
tree = estimator.tree_
feature = tree.feature[0] # 分裂特征
threshold = tree.threshold[0] # 分裂阈值
feature_name = 'u' if feature == 0 else 'v'
print(f"弱分类器 {i+1} 决策规则: {feature_name} <= {threshold:.4f}")
# 弱分类器错误率
error = [error1, error2][i]
print(f"弱分类器 {i+1} 加权错误率: {error:.4f}")
# 6. 可视化决策边界
def plot_decision_boundary(X, y, model, title):
h = 0.5 # 网格步长
x_min, x_max = X[:, 0].min() - 10, X[:, 0].max() + 10
y_min, y_max = X[:, 1].min() - 10, X[:, 1].max() + 10
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure(figsize=(8, 6))
plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.Paired)
plt.scatter(X[y==1, 0], X[y==1, 1], c='blue', label='蓝色样本', edgecolors='k')
plt.scatter(X[y==0, 0], X[y==0, 1], c='red', label='红色样本', edgecolors='k')
plt.xlabel('u')
plt.ylabel('v')
plt.title(title)
plt.legend()
plt.show()
# 绘制决策边界
plot_decision_boundary(X, y, adaboost, 'AdaBoost分类器决策边界 (2次迭代)')
(一)AdaBoostClassifier参数
-
base_estimator:弱分类学习器,理论上可以选择任何支持样本权重的分类器,默认是CART分类树DecisionTreeClassifier。如果算法选择SAMME.R,则弱分类学习器必须支持概率预测,即除了predict方法外,还需要有predict_proba方法。 -
n_estimators:弱学习器的最大迭代次数,默认为(50)。一般来说,n_estimators太小容易欠拟合,太大容易过拟合。 -
learning_rate:每个弱学习器的权重缩减系数,取值范围为(0)到(1),默认为(1.0)。较小的learning_rate意味着需要更多的弱学习器迭代次数,通常需要和n_estimators一起调参。 -
algorithm:可选参数,默认为SAMME.R。scikit - learn实现了两种Adaboost分类算法,SAMME和SAMME.R,两者的主要区别是弱学习器权重的度量,SAMME使用对样本集分类效果作为弱学习器权重,而SAMME.R使用对样本集分类的预测概率大小来作为弱学习器权重,SAMME.R迭代一般比SAMME快。 -
random_state:整数型,可选参数,默认为None,用于控制随机数生成,以确保结果的可重复性。
(二)AdaBoostRegressor参数
AdaBoostRegressor(base_estimator=None, n_estimators=50, learning_rate=1.0, loss='linear', random_state=None)
AdaBoostRegressor的参数与AdaBoostClassifier类似,其中loss参数是AdaBoostRegressor特有的,有线性'linear'、平方'square'和指数'exponential'三种选择,默认是线性,一般使用线性就足够了,除非怀疑该参数导致拟合程度不好。
更多推荐



所有评论(0)