决策树与集成学习入门:从 CART 到随机森林
如果说线性回归是机器学习的Hello World那么决策树就是机器学习中最贴近人类思维方式的算法。它把复杂的决策过程拆解成一系列是或否的判断就像一棵倒置的树——从根节点开始一步步分叉最终落到叶子节点得出结论。但决策树也有它的问题容易过拟合、结果不稳定。于是人们想到——一棵树不够就种一片森林。这就是集成学习的核心思想把多个弱模型组合起来得到一个强模型。今天这篇文章我们就来系统梳理 CART 决策树和集成学习的核心知识从决策树的构建原理到剪枝策略从 Bagging 到 Boosting再到随机森林的完整实现。一、决策树用如果…就…做决策基本概念决策树是一种树状结构的决策模型它把判断过程组织成一棵倒立的树——根在最上面叶子在最下面。一棵决策树由以下几部分组成根节点树的起始节点包含全部数据是第一个决策点内部节点中间的判断节点每个节点代表一个特征的判断分支连接节点的边代表判断的结果是/否或不同取值叶子节点终端节点代表最终的决策结果打个比方判断今天要不要出门。根节点是下雨了吗——如果下雨直接得出结论不出门叶子节点如果不下雨进入下一个判断温度合适吗——太热或太冷就不出门温度合适就出门。这就是一个典型的决策树思维过程。决策树的类型根据输出的不同决策树分为两类分类决策树叶子节点输出类别用于分类问题回归决策树叶子节点输出数值用于回归问题CARTClassification and Regression Tree决策树的两个核心特点是强制二分和逐层递归分裂。所谓强制二分就是每个内部节点只能分成两个分支左子树和右子树而不是多分。这使得 CART 树的结构更规整计算更高效。逐层递归分裂则是指从根节点开始找到最优分裂特征和分裂点把数据分成两部分然后对每个子节点重复这个过程直到满足停止条件。构建过程一棵决策树的构建大致分为五步选择最优特征找到让数据最纯的特征和分裂点作为当前节点的判断条件构建决策树根据分裂点把数据分到左右子树递归处理每个子节点剪枝去掉一些不必要的分支防止过拟合后面会详细讲叶子节点输出分类问题输出类别投票回归问题输出数值均值剪枝缓解过拟合通过剪枝提升泛化能力整个过程的核心问题是怎么判断哪个特征最优这就涉及到分裂标准——基尼系数、信息增益等。CART 决策树默认使用基尼系数来衡量节点的纯度基尼系数越小说明节点内样本越纯同类越多分裂效果越好。二、CART 决策树的优缺点CART 决策树之所以被广泛使用是因为它有很多显著的优点简单易懂。决策树的逻辑可以直接可视化——画成一棵树任何人都能看懂。这在需要向业务方解释模型时尤其重要你可以指着树说因为这个特征满足了这个条件所以预测结果是这样的。功能强大。既能处理分类问题也能处理回归问题既适用于数值型特征也适用于类别型特征不需要对数据做复杂的预处理不需要假设数据分布。规则简洁。每个节点的判断都是简单的条件语句没有复杂的数学公式。鲁棒性好。对缺失值不敏感对异常值的容忍度也高于线性模型。但决策树也有明显的缺点容易过拟合。决策树可以无限分裂下去直到每个叶子节点只有一个样本——这在训练集上准确率 100%但泛化能力极差。这是决策树最大的问题也是需要剪枝的根本原因。结果不稳定。数据的微小变化可能导致树的结构完全不同。因为每次分裂都选当前最优的特征如果数据有轻微扰动最优特征可能就变了整棵树的结构随之改变。不一定得到全局最优解。决策树采用贪心策略——每一步都选当前最优的分裂方式但局部最优不等于全局最优。也许某个特征在当前节点看不是最好的但在后续分裂中能带来更好的整体效果贪心策略会错过这种情况。三、API 调用scikit-learn 中决策树的 API 同样遵循三步走模式from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor # 分类决策树 clf DecisionTreeClassifier(criteriongini, max_depth5, random_state42) clf.fit(X_train, y_train) y_pred clf.predict(X_test) # 回归决策树 reg DecisionTreeRegressor(criterionsquared_error, max_depth5, random_state42) reg.fit(X_train, y_train) y_pred reg.predict(X_test)几个常用参数值得注意criterion分裂标准分类默认gini基尼系数回归默认squared_error均方误差max_depth树的最大深度控制模型复杂度防止过拟合min_samples_split节点分裂所需的最少样本数min_samples_leaf叶子节点最少样本数其中max_depth是最常用的调优参数配合 GridSearchCV 可以自动寻找最优深度。决策树还有一个很酷的功能——可视化from sklearn.tree import plot_tree import matplotlib.pyplot as plt plt.figure(figsize(20, 10)) plot_tree(clf, feature_namesfeature_names, class_namesclass_names, filledTrue) plt.show()运行后你会看到一棵完整的树每个节点显示了分裂特征、分裂值、基尼系数、样本数等信息直观展示了决策过程。四、实战案例泰坦尼克号生存预测决策树的经典实战案例是泰坦尼克号生存预测——根据乘客的性别、年龄、舱位等信息预测其是否在沉船事故中幸存。import pandas as pd from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder from sklearn.metrics import accuracy_score # 1. 加载数据 data pd.read_csv(titanic.csv) # 2. 数据预处理决策树的关键 # 处理缺失值 data[Age].fillna(data[Age].median(), inplaceTrue) data[Embarked].fillna(data[Embarked].mode()[0], inplaceTrue) # 类别特征编码 le LabelEncoder() data[Sex] le.fit_transform(data[Sex]) # male→1, female→0 data[Embarked] le.fit_transform(data[Embarked]) # 选择特征 features [Pclass, Sex, Age, SibSp, Parch, Fare, Embarked] X data[features] y data[Survived] # 3. 划分数据集 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) # 4. 训练决策树 clf DecisionTreeClassifier(max_depth5, random_state42) clf.fit(X_train, y_train) # 5. 评估 y_pred clf.predict(X_test) print(f准确率: {accuracy_score(y_test, y_pred):.4f})这个案例中数据预处理是重点。决策树虽然不需要标准化因为它不是基于距离的但需要处理缺失值和类别编码。与 KNN 相比决策树对特征量纲不敏感这是它的一大优势——省了标准化这一步。五、剪枝给决策树瘦身前面说到决策树最大的问题是容易过拟合。解决这个问题的核心手段就是剪枝。什么是剪枝剪枝顾名思义就是把不重要的内部节点删除用更合适的叶子节点替代。就像给果树剪枝——剪掉徒长的枝条让养分集中供给有价值的果实树才能长得更好。剪枝的目的很明确缓解过拟合提高模型的泛化能力。一棵长满所有分支的树在训练集上完美但在测试集上一塌糊涂剪掉一些枝叶后训练集准确率可能略有下降但测试集准确率会上升整体泛化能力更强。预剪枝预剪枝是在构建决策树的过程中进行剪枝。每生成一个新节点之前先判断这个节点分裂后模型在验证集上的精度是提升了还是下降了如果提升了就分裂如果下降了就不分裂直接把当前节点设为叶子节点。优点降低了模型的训练和验证时间不用生成完整的树实现简单边构建边判断缺点可能会剪掉后期有用的节点。某个节点当前看分裂收益不大但它的子节点可能带来很大收益。预剪枝因为短视错过了可能导致欠拟合常见的预剪枝手段包括限制树的最大深度max_depth、限制叶子节点最少样本数min_samples_leaf、限制分裂所需的最少样本数min_samples_split等。这些参数本质上都是在告诉树长到这个程度就别再长了。后剪枝后剪枝是先让决策树完整构建好再从底向上对内部节点逐一检查。对每个内部节点判断如果把这个节点替换成叶子节点剪掉它的所有子树验证集精度是提升还是下降如果提升就剪反之则保留。优点最大程度降低欠拟合风险。因为先让树充分生长再决定剪哪些不会因为短视而误剪通常效果好于预剪枝缺点训练和验证的时间长。先生成完整的树再从底向上逐一检查计算量更大实际项目中预剪枝更常用因为它简单高效配合网格搜索调参如搜索最优max_depth往往就能达到不错的效果。后剪枝效果更好但成本更高在对精度要求极高的场景下使用。六、集成学习三个臭皮匠顶个诸葛亮决策树虽然好用但单棵树的问题很明显——不稳定、容易过拟合。那有没有办法解决有——多种几棵树让它们一起决策。这就是集成学习的核心思想。集成学习的定义很简单把多个弱学习器组合成一个强大的学习器。单个模型可能不够准但多个模型各有所长组合起来就能取长补短效果远超单个模型。根据组合方式的不同集成学习主要分为三大流派Bagging并行集成、Boosting串行集成、Stacking堆叠集成。下面重点讲前两种。七、Bagging并行投票核心思想BaggingBootstrap Aggregating的思想可以概括为三步有放回的随机取样从原始训练集中有放回地抽取多个子集每个子集的大小和原数据集相同因为有放回所以每条样本可能被抽到多次也可能一次都没抽到并行计算每个子集独立训练一个弱学习器各学习器之间互不影响可以并行训练平权投票所有学习器的预测结果平等投票得票最多的就是最终结果分类问题回归问题则取平均值Bagging 的代表模型是随机森林Random Forest。随机森林随机森林 Bagging 思想 决策树。它在 Bagging 的基础上更进一步——不仅随机抽样本还随机抽特征。随机森林的实现原理从原始数据中随机抽取样本有放回Bootstrap 抽样从所有特征中随机抽取一部分特征比如从 100 个特征中随机选 20 个用抽到的样本和特征构建一棵决策树重复以上步骤生成多棵决策树比如 100 棵、500 棵预测时分类问题采用平权投票回归问题取均值为什么还要随机抽特征如果所有树都用全部特征那么每棵树的第一个分裂特征大概率是同一个最优特征导致所有树长得差不多多样性不足集成效果打折扣。随机抽取特征保证了每棵树的视角不同有的树看 A 特征有的树看 B 特征组合起来才能取长补短。随机森林的两个随机性样本随机 特征随机是它效果好的关键。API 调用from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor # 随机森林分类 rf RandomForestClassifier( n_estimators100, # 树的数量 max_depth10, # 每棵树的最大深度 max_featuressqrt, # 每棵树随机抽取的特征数sqrt表示√总特征数 random_state42 ) rf.fit(X_train, y_train) y_pred rf.predict(X_test)重要参数n_estimators树的数量越多效果越好但训练越慢通常取 100-500max_depth每棵树的最大深度控制单棵树的复杂度max_features随机抽取的特征数sqrt是常用默认值随机森林的优点很明显效果好、抗过拟合、可以并行训练、能输出特征重要性。缺点是模型不直观一百棵树没法像单棵树那样画出来给人看、计算量比单棵树大。八、Boosting串行纠错核心思想Boosting 的思路和 Bagging 完全不同——它是串行的不是并行的。Boosting 的核心思想第一个学习器先学学得不好的地方下一个学习器重点关注。就像接力赛跑每个选手接着上一个选手的位置继续跑一步步逼近正确答案。具体来说先训练第一个弱学习器得到预测结果计算预测错误的样本给这些样本加权重让下一个学习器更关注这些难样本用加权后的数据训练第二个学习器重复以上过程得到多个串行训练的学习器最终预测时按各学习器的表现加权投票学得好的模型权重高AdaBoostAdaBoostAdaptive Boosting是 Boosting 家族最经典的代表。它的自适应体现在每一轮都会根据上一轮的错误自动调整样本权重和学习器权重——错的样本权重升高对的降低准确率高的学习器投票权重高准确率低的投票权重低。AdaBoost 的优点是实现简单、效果不错缺点是对异常值敏感——异常值会被反复加权导致模型跑偏。Boosting 家族还有很多更强的成员GBDT梯度提升决策树用梯度下降的思路来优化XGBoost 和 LightGBM 在 GBDT 的基础上做了大量工程优化是数据竞赛中的大杀器。虽然导图中只提到了 AdaBoost但 GBDT/XGBoost 的核心思想和 Boosting 一脉相承——串行训练逐步优化。Bagging vs Boosting对比维度BaggingBoosting训练方式并行各模型独立串行模型依次训练样本权重每个样本权重相同错分样本权重逐渐升高投票方式平权投票加权投票好模型权重高目标降低方差提高稳定性降低偏差提高准确率代表随机森林AdaBoost、GBDT、XGBoost简单理解Bagging 是集体决策靠多样性取胜Boosting 是接力冲刺靠逐步优化取胜。九、学习心得与建议第一决策树是理解更复杂模型的桥梁。决策树本身可能不是最强的模型但它是理解随机森林、GBDT、XGBoost 等集成模型的基础。把决策树的分裂逻辑、过拟合问题、剪枝策略搞透后面学集成学习就水到渠成了。第二一定要画一次决策树。用plot_tree把树画出来看着每个节点的分裂条件和样本分布你对决策树的理解会比只看文字深刻得多。可视化是学习决策树最好的方式。第三随机森林是入门集成学习的最佳起点。它概念清晰、效果好、调参简单非常适合作为第一个集成学习模型来掌握。理解了随机森林的两个随机性再去看其他集成方法就有了参照系。第四集成学习不是万能的。集成学习确实能提升效果但也不是越复杂越好。随机森林虽然比单棵决策树强但训练慢、模型大、可解释性差。在效果达标的前提下优先选择更简单的模型——这是机器学习的铁律。写在最后从单棵决策树到一片随机森林我们看到了机器学习中一个经典的思路——单个模型不够好就用多个模型组合起来。这个思路看似朴素却支撑起了整个集成学习的大厦。今天我们梳理了 CART 决策树的构建原理、优缺点、剪枝策略以及集成学习的两大流派——Bagging以随机森林为代表和 Boosting以 AdaBoost 为代表。这些是树模型的基础也是后续学习 GBDT、XGBoost、LightGBM 等更强大模型的起点。机器学习的世界里没有哪个算法是孤立的。它们各有特色又彼此关联。理解它们之间的联系比死记硬背每个算法的细节更重要。如果这篇文章对你有帮助欢迎点赞收藏。下一篇我们将继续探索新的机器学习算法敬请关注。