通透!随机森林、AdaBoost、GBDT 对比 !!
- 2025-10-13 14:06:00
哈喽,大家好~
咱们今天来聊聊随机森林 vs AdaBoost vs GBDT:三大集成学习算法的系统对比。
首先,简单来说,随机森林采用并行的Bagging思想,用大量随机化的决策树来降低方差),鲁棒、几乎不容易过拟合,训练可并行化。
AdaBoost过“关注错分样本”的加权策略,把弱学习器串行地组合成强学习器,等价于逐次最小化指数损失的逐步加法模型。对噪声和离群点敏感。
GBDT(Gradient Boosted Decision Trees)把提升(boosting)推广为梯度下降的加法模型,每一步拟合当前负梯度(残差),可以用任意可微损失,灵活且效果强,但训练顺序性强(不易并行化)。
下面,咱们分开聊聊具体的算法模型~
随机森林
用bootstrap 重采样构建多棵决策树(每棵树训练不同的样本子集),并且在构造树的每个节点只随机考虑部分特征来寻找最佳分裂(feature bagging)。最后用多数投票(分类)或平均(回归)来融合多棵树的预测,从而显著降低方差而不明显增加偏差。
主要组成:
训练集:。 第 棵树在 bootstrap 样本上训练,表示为 ,总共有 棵树。 预测(回归): 预测(分类,多数投票):
假设每棵树的预测是均值为 ,方差为 ,树间的相关系数为 (pairwise correlation),则平均后的方差为:
解释:当 很小(树相互独立),方差近似为 ;若 接近 1,方差几乎不下降。随机森林通过样本随机化 + 特征随机化来减小 。
决策树中常用的分裂准则:
分类:Gini impurity 与 信息熵
Gini:
熵:
回归:最小化均方误差(MSE)(在节点用样本均值做预测)
AdaBoost
AdaBoost 是将弱学习器(通常是深度非常小的决策树 stump)串行地训练:每一轮根据前面模型的错误率调整样本权重,让后续弱学习器更“关注”被错分的样本。
最终加权投票得到强分类器。
换一个角度:指数损失的逐步最小化
AdaBoost 可以被看成在函数空间中做前向分步(forward stagewise)加法建模,目标是最小化指数损失
其中 ,, 是弱分类器(输出 )。
如何得到 与样本权重更新:
第一,在第 步,已知 ,想选 和 使 减小最多,即最小化
把 ,则问题变为最小化
第二,令 为在权重 下的加权错误率:
对 固定,关于 求导并令导数为 0,可得(经典结果):
第三,更新样本权重(归一化):
或等价地错分样本权重会放大,正确分类样本权重会缩小(按 )。
归一化常数 保证 和为 1:
AdaBoost = 前向逐步拟合指数损失,对噪声敏感,因为指数损失对错分点的惩罚非常高,含噪数据或标签错误会被不断放大权重,从而可能导致过拟合。
弱学习器要求,只要每轮的弱学习器的加权错误率 < 0.5,AdaBoost 就能产生强分类器(理论上错误率指数下降)。
并行化差,每一轮依赖前一轮的权重,天然串行。
GBDT
把模型表示为加法模型:
每一步根据当前模型残差(即目标函数对当前预测的负梯度)去拟合一个新树 ,然后用线搜索找到最优步长 。
换句话说,是在函数空间做梯度下降:每一步都沿着损失函数的负梯度方向增加一个基学习器。
GBDT 的强大之处在于:可以针对任意可微损失函数(回归的 MSE、分类的对数损失等)使用同样思想。
关键公式:
目标:最小化总体损失
初始化 (例如常数预测,最小化总体损失的常数):
对于 :
计算负梯度(pseudo-residuals):
拟合一个回归树 (通常用平方误差)去拟合 ,即最小化
对每个叶子做线搜索(或对于整棵树做一次步长确定),找到最优叶子输出 (若树有 J 片叶),常用的做法是对每个叶 (落在该叶的样本集合)计算
更新模型:
其中 是学习率(shrinkage),帮助正则化(小 更稳健,但需增大树的数量 )。
三者数学层面比较
模型形式:
Random Forest: ,平均(bagging)。
AdaBoost: ,通过权重 加权投票。目标等价于最小化指数损失。
GBDT: ,每一步拟合损失的负梯度(通用损失)。
损失函数:
RF:每棵树独立生长,树的分裂局部优化(如 MSE 或 Gini),整体没有直接全局损失函数被显式最小化(ensemble 是平均/投票)。
AdaBoost:全局损失是 指数损失 。
GBDT:直接最小化任意可微损失 ,用梯度步骤近似。
训练方式与并行性:
RF:每棵树相互独立 → 高度并行。
AdaBoost:轮间依赖权重 → 串行。
GBDT:序列地拟合残差 → 串行(但可以用近似并行技巧)。
对噪声/离群值的敏感性:
RF:相对稳健,对噪声不太敏感(因为平均能抵消)。
AdaBoost:敏感(指数损失对离群点惩罚大)。
GBDT:取决于损失函数,使用对数损失或 Huber 等可更稳健。
偏差-方差:
RF:主要目标是降低方差,某程度会略微增加偏差。
Boosting(AdaBoost/GBDT):通过串行纠错倾向于降低偏差,但可能增加过拟合(特别是 AdaBoost 在噪声下)。
GBDT 通过 shrinkage、subsampling、树限制等来控制过拟合。
总的来说,三者都不如单棵浅树直观,但 GBDT(尤其浅树 + 特征重要性 + SHAP)在工业里可解释性/贡献度分析工具更多。RF 也常用于特征重要性排序。
完整案例
我们生成一个带噪声的二维分类数据集,让三种模型去分类。
我们比较:
模型的决策边界(是否平滑 / 是否过拟合) 在不同训练样本数下的性能变化(学习曲线) 特征重要性的不同分布(模型解释性差异) 对噪声样本的敏感程度(鲁棒性)
完整代码实现:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split, learning_curve
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier, GradientBoostingClassifier
from sklearn.metrics import accuracy_score
import seaborn as sns
# 1. 数据集
X, y = make_moons(n_samples=1000, noise=0.3, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 2. 定义三种模型
rf = RandomForestClassifier(n_estimators=100, max_depth=5, random_state=42)
ada = AdaBoostClassifier(n_estimators=100, learning_rate=0.5, random_state=42)
gbdt = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1, max_depth=3, random_state=42)
models = {
"Random Forest": rf,
"AdaBoost": ada,
"GBDT": gbdt
}
# 3. 拟合模型并收集预测结果
for name, model in models.items():
model.fit(X_train, y_train)
# 准备绘制图像
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
plt.subplots_adjust(hspace=0.3, wspace=0.3)
cmap = plt.cm.rainbow # 鲜艳调色板
# 4. 图1:决策边界可视化
ax = axes[0, 0]
x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
xx, yy = np.meshgrid(np.linspace(x_min, x_max, 300),
np.linspace(y_min, y_max, 300))
for name, model in models.items():
Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
ax.contourf(xx, yy, Z, alpha=0.2, cmap=cmap)
ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cmap, edgecolor='k', s=30, label=name)
ax.set_title("Decision Boundaries Comparison", fontsize=15)
ax.legend()
ax.set_xlabel("Feature 1")
ax.set_ylabel("Feature 2")
# 5. 图2:学习曲线(训练/测试准确率随样本数变化)
ax = axes[0, 1]
for name, model in models.items():
train_sizes, train_scores, test_scores = learning_curve(model, X, y, cv=5,
train_sizes=np.linspace(0.1, 1.0, 8),
scoring="accuracy", n_jobs=-1)
train_mean = train_scores.mean(axis=1)
test_mean = test_scores.mean(axis=1)
ax.plot(train_sizes, train_mean, 'o-', label=f"{name} Train", alpha=0.8)
ax.plot(train_sizes, test_mean, '^-', label=f"{name} Test", alpha=0.8)
ax.set_title("Learning Curves", fontsize=15)
ax.set_xlabel("Training Samples")
ax.set_ylabel("Accuracy")
ax.legend()
# 6. 图3:特征重要性比较
ax = axes[1, 0]
importances = np.array([m.feature_importances_ for m in models.values()])
sns.barplot(x=["Feature 1", "Feature 2"],
y=importances.mean(axis=0),
palette="rainbow", ax=ax)
ax.set_title("Average Feature Importance", fontsize=15)
ax.set_ylabel("Importance")
# 7. 图4:对噪声的鲁棒性(添加不同噪声,测测试准确率)
ax = axes[1, 1]
noises = np.linspace(0.0, 0.5, 8)
acc_results = {name: [] for name in models}
for noise in noises:
Xn, yn = make_moons(n_samples=600, noise=noise, random_state=42)
Xn_train, Xn_test, yn_train, yn_test = train_test_split(Xn, yn, test_size=0.3, random_state=42)
for name, model in models.items():
model.fit(Xn_train, yn_train)
acc_results[name].append(accuracy_score(yn_test, model.predict(Xn_test)))
for name, acc in acc_results.items():
ax.plot(noises, acc, 'o-', label=name, linewidth=2)
ax.set_title("Noise Robustness Test", fontsize=15)
ax.set_xlabel("Noise Level")
ax.set_ylabel("Test Accuracy")
ax.legend()
plt.suptitle("Random Forest vs AdaBoost vs GBDT — Systematic Comparison", fontsize=18, fontweight='bold')
plt.show()

决策边界:随机森林边界平滑且稳定,AdaBoost容易追噪声过拟合,GBDT平衡了偏差与方差。 学习曲线:随机森林泛化稳定,AdaBoost训练高但易过拟合,GBDT整体精度最高且随样本增加持续提升。 特征重要性:所有模型识别关键特征,但AdaBoost权重偏极端,GBDT和RF估计更稳健。 噪声鲁棒性:随机森林最抗噪声,GBDT次之,AdaBoost最敏感。
总结对比结论
| 随机森林 | |||
| AdaBoost | |||
| GBDT |
总的来说,随机森林稳定且抗噪声,AdaBoost敏感易过拟合,GBDT兼顾高精度与稳健性,是三者在偏差、方差和鲁棒性上的典型取舍。
最后


扫码添加微信
- 点赞 (0)
-
分享
微信扫一扫
-
加入群聊
扫码加入群聊