机器学习实战:从零掌握集成学习(RF/XGBoost/GBDT/AdaBoost)—— 附泰坦尼克号、红酒分类、加州房价全流程解析

机器学习实战:从零掌握集成学习(RF/XGBoost/GBDT/AdaBoost)------ 附泰坦尼克号、红酒分类、加州房价全流程解析

作者:海宁不掉头发

发布时间:2026-07-08

阅读建议:本文适合有一定Python基础、刚入门机器学习的同学。


写在前面:为什么我要写这篇博客?

过去两周,我陷入了一种"调包侠"的焦虑:代码能跑通,准确率也不错,但一旦被问到"为什么XGBoost比随机森林快?""为什么网格搜索后准确率反而下降了?",我就哑口无言。

直到上周组会,导师的一句话点醒了我:"机器学习不是调API的艺术,而是理解数据流动和算法逻辑的修行。"

于是,我花了整整一周,重新梳理了最近学习的代码和案例------从线性回归、决策树,到随机森林、GBDT、XGBoost、AdaBoost,再到朴素贝叶斯和K-Means。我把每一个算法的底层逻辑、每一行代码的坑点、每一个实验的反直觉结果,都记录了下来。

这篇博客,既是我的学习笔记,也是一份"避坑指南"。我希望它能帮你少走弯路,真正从"会用"走向"理解"。


第一部分:基础铺垫 ------ 从决策树到集成学习

1.1 回归决策树 vs 线性回归:谁更懂数据的"弯弯绕绕"?

我们先从一个简单的问题开始:**如果数据不是直线,线性回归还能行吗?**或者说线性回归的模型图像一定要是直线嘛?期间有一个一直没有琢磨透的一个问题就是学习者必须要碰到的一个坑,什么是过拟合是什么是欠拟合,说白了就是过拟合就是学死板了,数据量太多了,不懂得里面的深层原理;或者在权重上面下功夫;比如说L1,L2正则化;另一方面欠拟合就是没学透,训练时间太短了,数据太少了;或者也可以采用Dropout(神技):在训练时随机让一部分神经元"放假"罢工,强迫剩下的神经元不能产生依赖,必须独立思考。

01_线性回归和回归决策树对比.py中,我做了一个小实验。

实验数据
复制代码
x_train = np.array(list(range(1, 11))).reshape(-1, 1)
y_train = np.array([5.56, 5.7, 5.91, 6.4, 6.8, 7.05, 8.9, 8.7, 9, 9.05])

这组数据肉眼可见不是一条直线。我们来看看两种模型的表现:

模型构建
复制代码
# 线性回归
estimator1 = LinearRegression()
# 回归决策树(深度1)
estimator2 = DecisionTreeRegressor(max_depth=1)
# 回归决策树(深度3)
estimator3 = DecisionTreeRegressor(max_depth=3)
结果可视化

https://img-blog.csdnimg.cn/img_convert/7a9c8b1c8d3e4c5a9b0d7e2f1a3b5c6d.png

我的发现

线性回归(红线):固执地拟合出一条直线,对于第7个点(8.9)这种"突变",它完全无能为力。

决策树(蓝线,深度1):找到了一个分界点(大约在第6个样本处),将数据分为两段,每段用一个常数值(均值)预测。这比直线灵活多了。

决策树(绿线,深度3):它几乎完美穿过了所有训练点。但这真的是好事吗?

核心思考

深度为3的决策树,在训练集上误差为0。但如果换一批新数据,它还准吗?这就是过拟合。决策树天生容易过拟合,因为它会把每一个细节都记下来,而不是总结规律。

一句话总结

线性回归假设世界是线性的,决策树则允许世界有"分段"的规律。但决策树太贪心,容易"死记硬背",这就需要集成学习来给它"降降温"。


1.2 集成学习:三个臭皮匠,顶个诸葛亮

既然单棵树容易过拟合,那能不能让多棵树一起决策?这就是**集成学习(Ensemble Learning)**的核心思想。

集成学习主要有两大门派:BaggingBoosting

Bagging(自助聚合):随机森林的故事

核心逻辑

有放回抽样:从原始数据中随机抽取样本,形成新的训练集(有些样本会被抽到多次,有些一次都抽不到)。这是自助聚合;就是随机森林的思想,是有放回的抽取

并行训练:用这些不同的数据集,并行训练多棵决策树。

平权投票:分类问题用投票,回归问题用平均。

代表算法:随机森林(Random Forest)。

代码见 02_随机森林算法_代码演示.py

复制代码
estimator2 = RandomForestClassifier() # 默认100棵树

随机森林在决策树的基础上,又加了一层随机性:不仅样本随机,特征也是随机选择的。这就保证了树的多样性,避免了所有树都长得一模一样。

Boosting(提升):从AdaBoost到GBDT

核心逻辑

  1. 串行训练:第一棵树训练完,第二棵树来"纠错",第三棵树再来纠正第二棵树的错......

  2. 加权投票:预测错的样本,在下一棵树中会被赋予更高的权重,逼着模型重点关注"难题"。

  3. 加法模型:最终的预测结果是所有树的预测结果的加权和。

代表算法:AdaBoost、GBDT、XGBoost。

AdaBoost代码示例 (03_AdaBoost算法_葡萄酒案例.py)

复制代码
estimator2 = AdaBoostClassifier(
    estimator=estimator1, 
    n_estimators=200, 
    learning_rate=0.1, 
    algorithm='SAMME'
)

AdaBoost的思路很直白:提高错分样本的权重。但它的一个问题是,对异常值非常敏感。而且AdaBoost就是对随机森林的升级版,加强版,在很多竞赛当中很多选手也喜欢用;

GBDT代码示例 (04_GBDT_泰坦尼克号案例.py)

复制代码
estimator2 = GradientBoostingClassifier()

GBDT(梯度提升决策树)比AdaBoost更进一步,它不再单纯调整样本权重,而是拟合上一棵树的残差(负梯度)。你可以把它理解为:第一棵树预测错了,留下了一个误差,第二棵树专门来学这个误差,第三棵树再学第二棵树留下的误差......最后把所有树的预测结果加起来,就是正确答案。不断的在前一棵树的结果上优化自己的结果,然后不断的调整。

关键区别

-随机森林:树之间互不干扰,砍掉任何一棵都不影响大局(并行)。

  • GBDT:树之间是师徒关系,后一棵树必须站在前一棵树的肩膀上(串行)。

第二部分:核心实战 ------ 泰坦尼克号生存预测

这是机器学习界的"Hello World"。在 02_随机森林算法_代码演示.py04_GBDT_泰坦尼克号案例.py中,我完成了从数据清洗到模型对比的全过程。

2.1 数据预处理:细节决定成败

导师常说:"数据决定了机器学习的上限,而模型和算法只是逼近这个上限。" 在这个案例中,我深刻体会到了这一点。

特征选择

我选择了三个最核心的特征:Pclass(船舱等级)、Sex(性别)、Age(年龄)。

复制代码
x = df[['Pclass', 'Sex', 'Age']].copy()
缺失值处理

Age列有177个缺失值。如果直接删除,会损失宝贵的信息。我采用了均值填充。对fillna方法进行整合函数和方法的补充是至关重要的,因为如果不填充满的话数据就会有趋势,模型就有训练不准确的风险,失之毫厘差以千里。

复制代码
x['Age'] = x['Age'].fillna(x['Age'].mean())

避坑点 :直接 x['Age'].fillna(...)可能会触发 Pandas 的 SettingWithCopyWarning。正确的做法是用 .copy()创建副本,或者在填充时指定 inplace=True

类别特征编码

计算机不认识 "male" 和 "female",所以需要转换成数字。我使用了独热编码(One-Hot Encoding)。独热编码通俗的讲:粗暴地讲,就是用"位置"来代表身份,全场只有一个人能发光。它是把一组非数字的文字标签(比如颜色、城市、动物),变成计算机能算得懂的"0和1阵列"的粗暴手段。

复制代码
x = pd.get_dummies(x)

独热编码会将 Sex列拆成 Sex_maleSex_female两列,用0和1表示。这样做的好处是避免了模型误以为性别之间存在大小关系(比如误以为 male > female)。

数据集划分

为了保证实验的可复现性,我固定了随机种子 random_state=23

复制代码
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=23)

2.2 模型对比:单棵树 vs 随机森林 vs GBDT

这是我实验中最精彩的部分。

实验结果
模型 测试集准确率 核心特点
单个决策树 (Baseline) 80.45% 容易过拟合,但作为基准线
随机森林 (默认参数) 81.56% 并行投票,鲁棒性强
GBDT (默认参数) 81.01% 串行纠错,拟合能力强
随机森林 (网格搜索) 80.45% 参数限制过死,性能倒退
GBDT (网格搜索) 78.79% 学习率过大+树太少,欠拟合
深度分析:为什么调参后反而变差了?

这是一个反直觉的结果。在 机器学习-第六周组会汇报.pptx中,我对此进行了深刻反思:

1. 交叉验证的"过度折损"

在网格搜索中,我设置了 cv=2(2折交叉验证)。泰坦尼克号数据集总共才891条数据,2折意味着每次只用445条数据训练。数据量太少,模型根本学不透,导致内部评估分数偏低。选出的"最优参数"其实是非常保守的。

2. 搜索空间的局限性

默认的随机森林是100棵树且不限制深度。但在网格搜索中,我人为限制了搜索范围:max_depth: [2, 3, 5, 7]。这相当于把一只鹰关在笼子里,让它跟鸡比跑步。最终选出的 (max_depth=5, n_estimators=30)组合,硬生生阉割了模型的潜力。

**3. GBDT的"步子太大"

在GBDT调参中,网格搜索选出了 learning_rate=0.5n_estimators=60。在小样本数据上,0.5的学习率意味着每一步的调整幅度非常大。模型还没来得及细细摸索,由于树的数量又限制在60棵,程序就戛然而止了。这就像学生做题速度极快但粗心大意,刚做了60道题考试就结束了,自然无法收敛到最优解。

我的改进计划

  1. 将交叉验证折数调整为 cv=5,提高稳定性。

  2. 放宽参数搜索空间,尊重模型的默认潜力。

  3. 对GBDT采用"小步快跑"策略:降低学习率(0.05-0.1),增加树的数量(100-300)。


第三部分:进阶挑战 ------ 红酒品质分类与XGBoost

如果说泰坦尼克号是"Hello World",那么红酒品质分类就是"Hard Mode"。在 01_xgboost_红酒品质分类案例.py红酒品质分类xgboost模型优化汇报.pptx中,我遭遇了样本不平衡代码逻辑漏洞的双重打击。

3.1 数据洞察:长尾分布的陷阱

红酒数据集共有6个品质等级(0-5),但分布极不均匀:

  • 多数类:类别2(中等品质)和类别3(中上品质)占据了绝大多数样本。

  • 少数类:类别0(极端劣质)只有2个样本,类别1只有11个样本,类别5(极端优质)只有3个样本。

这种长尾分布会导致一个严重问题:模型为了追求全局准确率,会倾向于预测多数类,而彻底忽略少数类。

3.2 代码复盘:一个"隐形"的Bug

在基线实验中,我的模型在测试集上取得了71.25%的准确率,看起来不错。但分类报告却揭示了残酷的真相:

类别 Precision Recall F1-Score Support
0 0.00 0.00 0.00 2
1 0.00 0.00 0.00 11
5 1.00 0.33 0.50 3

类别0和1完全失效! 模型对它们的识别率为0。

经过逐行排查代码,我发现了一个致命的逻辑漏洞:

复制代码
# 错误的代码
class_weight.compute_sample_weight('balanced', y_train)
# 正确的代码
sample_weights = class_weight.compute_sample_weight('balanced', y_train)
estimator.fit(x_train, y_train, sample_weight=sample_weights)

问题分析

compute_sample_weight函数确实计算了样本权重,但我没有将返回的权重数组赋值给任何变量,也没有将其传递给 fit()方法的 sample_weight参数。这意味着,这个平衡策略在训练阶段完全失效了!模型依然是在"裸奔"。

另一个坑点

XGBoost的 XGBClassifier不直接支持 class_weight参数。如果你在创建模型时传入 class_weight,它会直接报错或忽略。唯一正确的方式就是在 fit()中显式传入 sample_weight

3.3 XGBoost的底层魔法

尽管基线模型有问题,但XGBoost本身的强大毋庸置疑。在 California Housing Price Prediction.pdf随机森林 XGBoost训练数据对比.xlsx中,XGBoost展示了碾压级的性能:

指标 随机森林 XGBoost 提升幅度
MSE (均方误差) 0.2546 0.2166 降低14.9%
R² Score 0.8121 0.8401 提升2.8%
训练时间 12.38s 0.54s 快22.9倍

为什么XGBoost这么快?

Cache Access优化:它将频繁使用的梯度信息塞进CPU的高速缓存,避免了反复从内存读取数据的开销。

Block结构:它将数据预先排序,做成块(Block)结构,实现了特征维度的并行计算。

二阶泰勒展开:相比GBDT的一阶导数,XGBoost使用了二阶导数,收敛速度更快。

为什么XGBoost精度更高?

XGBoost采用了Boosting思想通过拟合残差逐步减小偏差(Bias) 。相比随机森林的简单平均,它对复杂规律的捕捉更加细腻。此外,它的目标函数中加入了正则化项(L1+L2),有效防止了过拟合。

3.4 优化方案:单一变量法的艺术

针对红酒分类的问题,我制定了系统的优化方案:

数据层面 :引入 SMOTE 过采样算法,人工合成少数类样本,解决"样本荒"。

模型层面 :修复 sample_weight的代码逻辑,让少数类在训练中拥有更高的话语权。

算法层面

复制代码
 将评估指标从 `accuracy`切换为 `f1_macro`,引导模型关注所有类别的平均表现,而不仅仅是准确率。
复制代码
 调整超参数:降低 `learning_rate`(如0.01-0.1),增加 `n_estimators`(如100-500),避免梯度震荡。

实验设计

我将设计三组对照实验:

仅使用SMOTE

仅修复权重传递

SMOTE + 权重传递

通过控制变量,量化每种策略对Macro-F1分数的贡献,从而沉淀出一套处理不平衡数据的标准方法论。


第五部分:总结与感悟

写完这篇博客,窗外已是深夜。回顾这两周的学习,我从只会调包,到现在能看懂分类报告里的F1-Score,能分析出网格搜索失败的原因,能发现代码中权重传递的逻辑漏洞。这种感觉,比单纯跑出一个高准确率要踏实得多。

我的几点核心感悟

警惕"伪高分":Accuracy(准确率)在不平衡数据面前一文不值。要学会看Precision、Recall、F1-Score,尤其是Macro Avg。

尊重数据stratify=yrandom_state=23.copy(),这些工程细节看似琐碎,却是实验严谨性的基石。

理解底层 :知道XGBoost为什么快(Cache、Block),比知道它快更有用。知道GBDT拟合残差的道理,比会用 GradientBoostingClassifier更重要。

单一变量法:调参不是"炼丹"。每次只改变一个变量,才能看清参数对模型的影响。这是我本周学到的最重要的科研方法。

未来的路

下周,我将继续深入研究LightGBM和CatBoost,并完成红酒分类的优化实验。我希望能将"样本权重传递"、"SMOTE过采样"和"评估指标选择"这三个关键点,内化成自己的肌肉记忆。

致谢

感谢导师的严厉指正,感谢同门的交流讨论,也感谢那个即使debug到凌晨两点也没有放弃的自己。

源码获取

本文涉及的所有代码和数据集,均已上传至我的GitHub仓库:


如果你觉得这篇博客对你有帮助,欢迎点赞、收藏、关注。让我们一起在机器学习的路上,走得更远、更稳。


附录:核心代码片段速查

1. 分层抽样与权重计算

复制代码
from sklearn.model_selection import train_test_split
from sklearn.utils import class_weight

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=23, stratify=y)
sample_weights = class_weight.compute_sample_weight('balanced', y_train)

2. XGBoost正确注入权重

复制代码
import xgboost as xgb
model = xgb.XGBClassifier(objective='multi:softmax')
model.fit(x_train, y_train, sample_weight=sample_weights)

3. 网格搜索配合分层K折

复制代码
from sklearn.model_selection import GridSearchCV, StratifiedKFold
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=23)
param_grid = {'max_depth': [3, 5, 7], 'learning_rate': [0.01, 0.1]}
grid_search = GridSearchCV(model, param_grid, cv=skf, scoring='f1_macro')
grid_search.fit(x_train, y_train)

本文为原创内容,转载请注明出处。

相关推荐
人工智能培训17 小时前
破解数据发展瓶颈 激活数字经济新动能
大数据·数据库·人工智能·深度学习·神经网络·机器学习·生成对抗网络
大鱼>17 小时前
AI+货物追踪:智能快递柜追踪系统
人工智能·深度学习·算法·机器学习
凉云生烟19 小时前
机器学习 02- KNN算法
人工智能·算法·机器学习
向哆哆20 小时前
高质量人体检测与行人识别数据集分享(适用于YOLO系列深度学习分类检测任务)
深度学习·yolo·目标检测·分类
lisw0521 小时前
【心理学】什么是人性化管理?如何实施人性化管理?
人工智能·机器学习·软件工程
CClaris21 小时前
大模型量化从0到1(五):GPTQ 原理详解 + 从零量化一个真实大模型
人工智能·python·算法·机器学习
大鱼>1 天前
AI+货物追踪:贵重物品智能追踪系统
人工智能·深度学习·算法·机器学习
大鱼>1 天前
AI+货物追踪:集装箱智能追踪系统
人工智能·深度学习·算法·机器学习
z小猫不吃鱼1 天前
模型剪枝经典论文精读:NISP: Pruning Networks using Neuron Importance Score Propagation
算法·机器学习·剪枝