1. 引言:随机森林算法是什么在机器学习中单棵决策树虽然直观、易于理解却容易受到训练数据变化的影响即使只增加或删除少量样本也可能产生一棵结构明显不同的树。为了获得更稳定的预测我们可以训练多棵决策树再将它们的结果进行聚合。在上一篇文章中我们介绍了 BaggingBootstrap Aggregating思想通过有放回抽样构造不同的训练集分别训练多个模型再通过投票或平均得到最终预测。随机森林Random Forest正是在这一思路上发展起来的经典集成算法。不过⭐训练集不同就一定能得到足够不同的决策树吗假如某个特征的预测能力很强即使各棵树使用的样本有所不同它们仍可能优先选择这个特征形成相似的划分规则。当多棵树容易在相似的样本上犯错时仅仅增加树的数量带来的改善就可能受到限制。随机森林进一步引入了特征随机性在每个节点分裂时随机抽取一部分特征作为候选再从中寻找最佳划分。它希望在保留单棵树预测能力的同时降低树之间的相关性让多棵树的预测更具互补性。这里我先给一个公式方便大家理解随机森林 Bagging 集成思想 决策树作为基学习器 随机特征选择本文将简要回顾 Bagging重点分析它的功绩与瓶颈以及随机森林如何通过特征随机性进行改进最后结合算法流程与 Python 实战理解随机森林如何训练、预测与评估。2. 前提回顾Bagging 的核心思想Bagging 的完整原理可以参考前文这里只回顾理解随机森林所需的三个步骤。有放回抽样从原始训练集中有放回地随机抽取多个子集每个子集的大小与原数据集相同但其中可能包含重复样本。并行训练在每个子集上独立训练一个基学习器各学习器之间互不干扰。结果聚合对于分类任务采用投票法决定最终类别对于回归任务采用取平均值的方式得到最终预测结果。2.1 有放回抽样生成不同训练集假设原始训练集包含 (N) 个样本。每次从中随机抽取一个样本抽取后放回重复 (N) 次得到一份 Bootstrap 训练集。由于采用有放回抽样某些样本可能出现多次。某些样本可能没有被抽中。不同轮次得到的训练集通常有所不同。重复这一过程就可以构造多份训练集。2.2 并行训练让模型分别学习在每份训练集上分别训练一个基学习器其中(B) 表示基学习器的数量。这些模型之间没有必须按顺序学习的依赖关系因此可以并行训练。2.3 结果聚合共同给出预测对于回归任务通常取各模型预测的平均值对于分类任务常见的思路是多数投票也可以在基模型提供类别概率时先平均概率再选择概率最大的类别。Bagging 的基本流程可以概括为样本扰动 → 分别训练 → 预测聚合回顾这三个步骤我们发现了一个问题 - Bagging思想并没有保证训练出来的模型一定具有足够大的差异接下来让我们详细分析一下。3. Bagging 的功绩与瓶颈树多还需要差异3.1 功绩降低预测方差决策树尤其是生长较深的决策树这种深决策树是低偏差、高方差的模型。对训练数据的变化往往比较敏感。例如训练集中增加或删除少量样本可能改变某个节点的最佳划分而这个节点的变化又会影响后续整棵子树训练数据的微小扰动就会让它面目全非。这意味着虽然单棵树可以拟合非常复杂的交互结构但在不同训练集上训练得到的决策树可能给出波动较大的预测。Bagging 通过平均来“平滑”这种波动而不损害其拟合能力将多棵树的预测进行聚合可以减弱单棵树波动对最终结果的影响。它尤其适合决策树这类对数据扰动比较敏感的学习器。不过平均能够带来多大收益还取决于这些预测之间的相关性。3.2 用一个方差公式理解瓶颈1. 为什么固定输入后树的预测还有方差对于固定输入 (x)例如同一套房屋的特征。如果训练数据和训练过程都固定一棵树的预测当然是确定的。但当我们改变训练样本或训练随机性时得到的树会不同对这个 (x) 的预测也可能不同,我们先分析一棵树的方差,即。因此我们把预测看作随机变量并简写为森林对这个输入的平均预测为我们要计算的就是​​​​ ​2. 先理解两棵树的情况两个随机变量相加方差公式是其中协方差描述两个预测是否倾向于一起变化。假设两棵树预测的方差都是相关系数都是。根据相关系数的定义于是再利用得到两棵树平均预测的方差​​​​​​​ ​​​​​​​看两个特殊情况就容易理解如果0 平均后的方差为/2。如果1平均后的方差仍为。因为我们假设的是预测的方差都是,即两棵树如果完全同步波动这种情况下取平均也无法抵消这种波动。3. 推广到B棵树多个随机变量之和的方差为​​​​​​​ ​​​​​​​右边有两部分。第一部分各棵树自身的方差。一共有B棵树假设每棵树的预测方差为所以​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​第二部分不同树之间的协方差。从B棵树中选两棵共有组合数:​​​​​​​ ​​​​​​​ ​​​​​​​每一对的协方差都是再乘公式前面的系数2得到​​​​​​​ ​​​​​​​求平均相当于乘上所以方差要乘上​​​​​​​这个公式揭示了两个影响因素树的数量 (B)增加树的数量可以缩小第二项。树之间的相关性 ()相关性越高聚合后保留的共同波动越明显。4. 为什么它能说明 Bagging 的瓶颈把结果拆成两项​​​​​​​ ​​​​​​​假设单棵树的预测方差为 100树之间的相关系数为 0.3则树的数量 (B)平均预测的方差1100103710030.7100030.07趋于无穷大趋于 30即用公式表示:​​​​​​​ ​​​​​​​ ​​​​​​​可以看到增加树的数量收益逐渐减小。因此在上述假设下在单树方差和相关系数保持不变的假设下剩下的共同波动(相关性带来的那部分方差)无法靠继续增加树来消除。​​ ​​​需要注意这个公式用于解释平均预测的方差不能直接当作分类错误率公式也不能覆盖真实森林中的全部复杂因素。4. 随机森林的破局引入特征随机性4.1 从“全部特征中选最好”到“候选特征中选最好”随机森林作为 Bagging 思想的典型代表在实际应用中展现出诸多优势同时也存在一些局限性。随机森林的关键改动发生在决策树的节点分裂过程中。普通决策树通常从全部特征中寻找最佳划分。随机森林则在每个节点从全部 p 个特征中随机选取 m 个候选特征。只在候选特征范围内搜索划分。选择其中效果最好的特征与划分点。进入子节点后重新抽取候选特征。例如某个节点随机获得的候选集合是​ ​​​​​​​那么即使“房屋面积”在全部特征中最有优势它也无法参与这个节点的分裂竞争。这让其他特征获得了参与构建决策规则的机会。随机的是候选特征集合候选集合内仍然要寻找优质划分。随机森林并不是随意选择一个特征再随意切一刀。4.2 两种随机性分别作用在哪里随机性发生位置主要作用样本随机性每棵树训练前让不同树看到不同的样本组合特征随机性每个节点分裂时让不同节点面对不同的候选特征集合这里容易混淆的一点是经典随机森林的特征抽样发生在每个节点而不是只在每棵树开始训练时抽取一次。举例说明:假设任务是分类总特征数 N100。根据公式​每次节点分裂时抽取的特征数 m10。1. 根节点第一次分裂算法从全部100个特征中随机、独立地抽取10个特征假设抽到了编号 3, 15, 28, 42, 55, 61, 77, 80, 92, 99。在这10个特征中寻找最佳分裂点。假设最终使用了特征15进行分裂。2. 左子节点第二次分裂注意此时算法重新从全部100个特征中随机抽取10个假设这次抽到了 1, 2, 3, 4, 5, 15, 20, 30, 40, 50。在这新的10个特征中找最佳分裂点。假设使用了特征2。3. 右子节点第三次分裂再次从全部100个特征中随机抽取10个假设抽到了 10, 20, 30, 40, 50, 60, 70, 80, 90, 100。找最佳分裂点假设用了特征90。以此类推直到树长满。因此一棵树的根节点和后续节点可能使用不同的候选特征集合。4.3 为什么特征越随机效果不一定越好既然随机性能够增加差异是否应该把候选特征数量降得越低越好答案是否定的。当候选特征太少时某些节点可能无法获得足够有用的特征导致划分质量下降单棵树的预测能力受到影响。因此随机森林需要平衡两个目标单棵树需要有一定的预测能力。不同树之间需要有足够的差异。对上面出现的候选特征公式深入理解一下为什么是“根号N”这是一个偏差-方差权衡Bias-Variance Tradeoff的经验法则如果 m 太大比如接近 N每次分裂都能看到大多数特征单棵树会很强偏差小但树与树之间的差异会变小变得高度相关。这会导致集成后的整体方差降不下来失去了随机森林抵抗过拟合的优势。如果 m 太小树与树之间差异很大方差小但单棵树因为能看的特征太少可能长得很差偏差大。​是一个在“保持单棵树一定准确率”和“降低树与树之间相关性”之间取得良好平衡的经验值(分类时)。候选特征数量较大时单棵树有更多机会找到好的划分但不同树也可能更加相似候选特征数量较小时树之间的差异可能增大但单棵树也可能变弱。随机森林追求的是有效的差异而不是随机性本身。4.4 决策树、Bagging 与随机森林的区别对比项单棵决策树Bagging 决策树经典随机森林模型数量一棵多棵多棵每棵树的训练样本通常使用完整训练集Bootstrap 抽样Bootstrap 抽样节点候选特征通常为全部特征通常为全部特征随机特征子集预测方式单树预测聚合多树预测聚合多树预测核心思路学习划分规则通过聚合降低波动在聚合基础上进一步降低相关性这里的 Bagging 决策树指采用常规全特征决策树作为基学习器的配置Bagging 本身是更一般的框架也可以搭配其他学习器或特征抽样策略。5. 随机森林算法训练与预测流程5.1 训练过程设训练集为​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​每个样本包含 p 个特征森林包含 B 棵树每个节点抽取 m 个候选特征。训练过程如下输入训练集 D树的数量 B候选特征数量 m对 b 1, 2, ..., B1. 从 D 中进行 Bootstrap 抽样得到训练集 D_b2. 使用 D_b 构建决策树对每个需要分裂的节点a. 随机抽取 m 个候选特征b. 在候选特征中寻找最佳特征和划分点c. 按照最佳划分生成子节点d. 重复上述过程直到满足停止条件3. 保存决策树 h_b输出由 B 棵决策树组成的森林停止条件可以包括最大深度、节点样本数不足、无法继续有效分裂等。经典随机森林通常使用生长较深的树实际应用中也可以通过参数限制复杂度。5.2 节点如何判断划分好坏以分类任务常用的基尼不纯度为例中表示节点 t 中第 k 类样本的比例。节点中的类别越混杂基尼不纯度通常越高如果全部样本属于同一类则​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​对于某个候选划分其不纯度下降量可以写为​​​​​​​ ​​​​​​​算法在允许的候选范围内寻找使最大的划分。随机森林改变了参与竞争的特征范围节点内部仍然遵循决策树的划分原则。5.3 预测过程对于回归任务对所有树的预测取平均​​​​​​​ ​​​​​​​ ​​​​​​​对于分类任务常见的概念描述是多数投票​​​​​​​ ​​​​​​​简单理解核心动作“数人头”。每棵树只给出一个确定的类别比如A或B然后大家直接投票少数服从多数。盲区不管树有多确信也只是一票。极度确信的树和瞎猜的树权重是一样的。不过在本文使用的 scikit-learn 中RandomForestClassifier会先平均各棵树给出的类别概率再选择平均概率最大的类别简单理解核心动作“算平均分”。每棵树给出的是自己预测各个类别的概率。先所有树把概率加起来求平均最后谁的平均概率最高就选谁。优势它考虑了树的“确信程度”。如果一棵树极度确信是A即使别的树稍微偏向B求平均后A依然能胜出。概率平均与硬投票并不总是产生相同结果。阅读算法介绍与实际代码时需要区分概念描述和具体实现。5.4 袋外评估利用未被抽中的样本一次 Bootstrap 抽样中某个样本在一次抽取时没有被选中的概率为​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​连续抽取 N 次都没有选中它的概率为​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​当 N 足够大时也就是说一棵树进行等量 Bootstrap 抽样后平均约有36.8% 的训练样本没有参与这棵树的训练这些样本称为该树的袋外样本。对于每个训练样本可以只汇总那些没有使用过它的树所给出的预测再计算整体指标这就是袋外评估OOB。这里要注意不同树对应的袋外样本集合不同。36.8% 是上述抽样条件下的近似比例。如果反复根据 OOB 分数选择参数OOB 也参与了模型选择仍应保留独立测试集做最终评估。不会有人对这块看不懂吧那我来给你举个例子你带入到上面再想一想36.8%是怎么来的假设你有一个袋子里面有 N 个球代表 N 个训练样本。重复这个过程 N 次最后求极值就好啦。OOB到底是什么假设你的整个数据集有 1000 个样本。你训练了 100 棵树。现在我们盯住其中的第 42 号样本看看红框里的话是怎么操作的第一步找没用过它的树。在这 100 棵树里每一棵树都有约 36.8% 没见过的数据。所以必定有几十棵树在训练时没有抽中第 42 号样本。第二步只让这些树给它打分。我们把那些在训练时见过 42 号样本的树全部踢掉只保留那些没见过它的树。让这几十棵树对 42 号样本进行预测投票或算概率。第三步对比真实答案。这几十棵“瞎眼”的树给出了一个综合预测结果。我们拿这个结果和 42 号样本的真实标签比一比看预测对不对。把上面的过程对全部 1000 个样本都做一遍。每一个样本都只由那些“没在训练时见过它”的树来预测。最后算出一个总的准确率或误差。这就叫袋外评估OOB Error / OOB Score。5.5 关键参数参数含义主要影响n_estimators树的数量影响聚合稳定性、训练时间与模型大小max_features每个节点考虑的候选特征数量调节单树能力与树间差异max_depth单棵树最大深度限制树的复杂度min_samples_leaf叶节点最小样本数避免叶节点只拟合极少量样本max_samplesBootstrap 抽样规模控制每棵树使用的样本量bootstrap是否采用有放回抽样决定是否引入该类样本随机性oob_score是否计算袋外得分在 Bootstrap 配置下提供内部评估random_state随机种子帮助复现实验增加树的数量通常会让预测逐渐稳定但收益可能趋于饱和。若主要问题是信息不足、数据泄漏或单树设置不合理单纯增加树的数量也无法解决。6. Python 实战基于泰坦尼克号数据预测乘客生存情况理解随机森林的原理后我们通过泰坦尼克号乘客生存预测任务观察单棵决策树与随机森林的表现并使用网格搜索寻找更合适的参数。本节设置三个实验场景单棵决策树。使用默认主要参数的随机森林。通过网格搜索调参的随机森林。通过对照实验我们重点观察多树集成是否改善了模型的泛化表现以及限制树的复杂度能否进一步提高预测效果。6.1 任务说明与数据准备本次使用titanic_train.csv数据根据乘客信息预测其是否生还。选取以下三个特征字段含义处理方式Pclass船票等级保留数值形式Sex性别独热编码Age年龄使用训练数据的平均值填充缺失值预测目标为Survived0未生还。1生还。这里只选择三个特征便于理解从数据处理到模型评估的完整流程。实际任务中还可以进一步探索票价、登船港口、同行亲属数量等信息。6.2 数据预处理先划分再学习填充规则年龄特征存在缺失值可以使用平均值进行填充。但均值应仅根据训练数据计算避免测试集的信息提前参与建模。因此需要遵循以下顺序划分训练集与测试集 → 根据训练集学习预处理规则 → 将相同规则应用到测试集。交叉验证时也一样每一折的填充规则都应只从该折的训练部分学习。本节使用Pipeline和ColumnTransformer将以下操作连接起来对Age使用平均值填充。对Sex使用众数填充再进行独热编码。对Pclass保留数值形式。将处理后的特征交给分类模型。这样预处理会随模型一起参与交叉验证避免提前利用验证数据的信息。划分数据时还使用stratifyy使训练集与测试集中的类别比例尽量接近原始数据。6.3 场景一训练单棵决策树首先训练一棵决策树作为后续实验的对照基线DecisionTreeClassifier(random_state23)模型训练完成后分别计算训练集与测试集准确率model.score(x_train, y_train) model.score(x_test, y_test)训练集准确率反映模型对已见数据的拟合程度测试集准确率则用于评估模型对未见数据的预测表现。如果训练准确率很高而测试准确率明显较低就需要警惕过拟合。因此不能仅凭训练集上的高分判断模型效果。6.4 场景二训练随机森林接下来训练随机森林RandomForestClassifier( random_state23, n_jobs-1, )这里保留默认的主要建模参数只设置随机种子和并行计算。其中random_state控制随机过程便于复现实验。n_jobs-1允许使用所有可用处理器核心并行训练。随机森林通过样本随机性和节点特征随机性构建多棵决策树再聚合各棵树的预测结果。我们将比较它与单棵决策树的训练、测试准确率观察集成是否改善了当前任务中的泛化表现。6.5 场景三使用网格搜索调整随机森林参数默认参数提供了建模起点但不一定适合当前数据。本次设置以下参数搜索范围{ n_estimators: [60, 90, 100, 130, 150], max_depth: [3, 5, 7, 9], }两个参数分别控制参数含义本次实验关注点n_estimators森林中树的数量增加树的数量能否改善预测表现max_depth单棵树的最大深度限制树的复杂度能否改善泛化表现共有 5 * 4 20组候选参数。结合三折交叉验证需要完成20 * 3 60次候选模型拟合。搜索结束后GridSearchCV默认还会使用最佳参数在完整训练集上重新拟合模型。由于分类器放在流水线的model步骤中搜索参数名称需要增加model__前缀{ model__n_estimators: [60, 90, 100, 130, 150], model__max_depth: [3, 5, 7, 9], }网格搜索前不需要单独训练分类器直接调用GridSearchCV.fit()即可。6.6 完整代码以下代码包含数据加载、预处理、三个场景的模型训练以及结果对比。运行前请根据数据文件的实际位置修改DATA_PATH。from pathlib import Path import pandas as pd from sklearn.compose import ColumnTransformer from sklearn.ensemble import RandomForestClassifier from sklearn.impute import SimpleImputer from sklearn.metrics import classification_report, confusion_matrix from sklearn.model_selection import ( GridSearchCV, StratifiedKFold, train_test_split, ) from sklearn.pipeline import Pipeline from sklearn.preprocessing import OneHotEncoder from sklearn.tree import DecisionTreeClassifier # 根据实际文件位置修改路径 DATA_PATH Path(../data/titanic_train.csv) RANDOM_STATE 23 def build_pipeline(model): 将数据预处理与分类模型组合。 # 年龄使用当前训练数据的平均值填充 age_transformer SimpleImputer(strategymean) # 性别使用众数填充再进行独热编码 sex_transformer Pipeline([ (imputer, SimpleImputer(strategymost_frequent)), ( encoder, OneHotEncoder(handle_unknownignore), ), ]) # 对不同列分别进行处理 preprocessor ColumnTransformer([ (age, age_transformer, [Age]), (sex, sex_transformer, [Sex]), (pclass, passthrough, [Pclass]), ]) return Pipeline([ (preprocessor, preprocessor), (model, model), ]) def evaluate_model(name, model, x_train, x_test, y_train, y_test): 记录训练集与测试集准确率。 return { 模型: name, 训练集准确率: model.score(x_train, y_train), 测试集准确率: model.score(x_test, y_test), } def main(): # 1. 加载数据 data pd.read_csv(DATA_PATH) x data[[Pclass, Sex, Age]].copy() y data[Survived] print(数据规模, x.shape) print(\n特征缺失情况) print(x.isna().sum()) # 2. 划分训练集与测试集 x_train, x_test, y_train, y_test train_test_split( x, y, test_size0.2, random_stateRANDOM_STATE, stratifyy, ) results [] # 3. 场景一单棵决策树 tree build_pipeline( DecisionTreeClassifier( random_stateRANDOM_STATE, ) ) tree.fit(x_train, y_train) results.append( evaluate_model( 单棵决策树, tree, x_train, x_test, y_train, y_test, ) ) # 4. 场景二保留默认主要参数的随机森林 forest build_pipeline( RandomForestClassifier( random_stateRANDOM_STATE, n_jobs-1, ) ) forest.fit(x_train, y_train) results.append( evaluate_model( 默认随机森林, forest, x_train, x_test, y_train, y_test, ) ) # 5. 场景三网格搜索随机森林 # 搜索阶段由 GridSearchCV 并行 # 单个森林内部使用一个工作进程避免嵌套并行。 search_pipeline build_pipeline( RandomForestClassifier( random_stateRANDOM_STATE, n_jobs1, ) ) param_grid { model__n_estimators: [60, 90, 100, 130, 150], model__max_depth: [3, 5, 7, 9], } cv StratifiedKFold( n_splits3, shuffleTrue, random_stateRANDOM_STATE, ) search GridSearchCV( estimatorsearch_pipeline, param_gridparam_grid, scoringaccuracy, cvcv, n_jobs-1, refitTrue, ) search.fit(x_train, y_train) results.append( evaluate_model( 网格搜索随机森林, search, x_train, x_test, y_train, y_test, ) ) # 6. 输出三个模型的评估结果 result_df pd.DataFrame(results).set_index(模型) print(\n模型评估对比) print(result_df.round(4).to_string()) # 去掉流水线参数前缀方便阅读 best_params { key.replace(model__, ): value for key, value in search.best_params_.items() } print(\n最佳参数) print(best_params) print( \n最佳参数对应的交叉验证平均准确率 f{search.best_score_:.4f} ) # 7. 查看交叉验证排名靠前的参数组合 cv_results pd.DataFrame(search.cv_results_) columns [ param_model__n_estimators, param_model__max_depth, mean_test_score, std_test_score, rank_test_score, ] print(\n交叉验证排名前五的参数组合) print( cv_results[columns] .sort_values(rank_test_score) .head(5) .to_string(indexFalse) ) # 8. 查看调参模型的详细测试结果 y_pred search.predict(x_test) print(\n测试集前十条预测) prediction_df pd.DataFrame({ 真实值: y_test.to_numpy(), 预测值: y_pred, }) print(prediction_df.head(10).to_string(indexFalse)) print(\n分类报告) print( classification_report( y_test, y_pred, labels[0, 1], target_names[未生还, 生还], digits4, zero_division0, ) ) print(\n混淆矩阵) print( confusion_matrix( y_test, y_pred, labels[0, 1], ) ) if __name__ __main__: main()本例保留性别独热编码的全部类别列。对决策树而言不需要像某些线性模型那样为避免完全共线性而专门删除其中一列。6.7 实验结果如何分析代码运行后会输出模型对比表、最佳参数、交叉验证得分、分类报告和混淆矩阵。具体数值以实际运行结果为准。分析时应重点回答以下问题。1随机森林是否改善了测试表现首先比较单棵决策树与默认随机森林的测试准确率。如果随机森林更高说明在当前数据划分和参数配置下多树集成带来了泛化收益。如果两者接近甚至随机森林略低也应如实记录。数据规模、特征信息与参数设置都会影响最终表现。随机森林并不保证在每一次数据划分中都优于单棵决策树。2限制树深度后模型表现发生了什么变化比较默认随机森林与网格搜索随机森林的训练、测试准确率。如果最佳参数选择了较小的max_depth模型的训练准确率可能下降但测试准确率可能提高。这说明限制树的复杂度可能减少了对训练细节的拟合。不过不能只看训练与测试分数的差距。如果两个分数都很低即使差距很小也可能存在欠拟合。因此需要同时观察训练集上的拟合程度。测试集上的预测表现。二者之间的差距。3交叉验证得分与测试得分有什么区别search.best_score_表示最佳参数组合在训练集内部的交叉验证平均准确率。而search.score(x_test, y_test)表示模型在独立测试集上的准确率。两者使用的数据不同结果不必相同。此外最佳参数只是当前候选范围、评价指标与交叉验证划分下的最佳选择并不代表所有参数组合中的全局最优。4为什么不能只看准确率准确率反映整体预测正确的比例但不能完整展示不同类别的识别情况。分类报告中的主要指标包括指标含义Precision被预测为某一类的样本中实际属于该类的比例Recall实际属于某一类的样本中被正确识别的比例F1-score精确率与召回率的调和平均Support该类别在评估数据中的样本数量混淆矩阵则可以进一步展示错误的方向。本例固定类别顺序为[0, 1]其结构为​​​​​​​结合这些指标才能更具体地理解模型在哪些样本上容易出错。6.8 本案例的边界与改进方向本案例展示了从单棵决策树到随机森林再到参数搜索的完整流程但还不能单独证明特征随机性的作用。原因是单棵树与随机森林之间同时存在样本抽样、多树聚合和特征随机性等差异。如果希望专门研究特征随机性可以在其他设置相同的情况下对比不同的max_features配置。后续还可以从以下方向改进丰富特征信息加入票价、登船港口、家庭规模等变量。扩展参数搜索加入max_features、min_samples_leaf等参数。完善验证方式在训练集内部比较候选方案保留独立测试集用于最终评估。特别需要注意不能在查看测试结果后反复根据测试分数修改特征和参数否则测试集也会逐渐参与模型选择失去独立评估的意义。这个案例的重点不仅是调用随机森林接口更是建立完整的建模思路先建立基线再引入集成与参数搜索最后通过独立评估判断改进是否有效。7. 总结从决策树到 Bagging再到随机森林可以看到一条清晰的改进路线单棵决策树容易受到训练数据变化的影响Bagging 通过训练多棵树并聚合预测减弱这种波动随机森林进一步限制每个节点的候选特征尝试降低树之间的相关性。它的核心启示是集成模型的效果既取决于个体是否具有预测能力也取决于不同个体能否提供互补信息。随机森林能够学习非线性关系和特征交互通常不需要为了树的划分专门进行特征标准化因此适合作为表格数据任务的重要基线模型。同时它也有实际限制树的数量增加会带来计算和存储成本整体规则比单棵树更难直接解释标准回归森林通过叶节点预测再求平均也不擅长外推到训练目标取值范围之外。回到文章开头的问题为什么已经有了 Bagging还需要特征随机性因为让模型看到不同的样本只是制造差异的一种方式让模型在不同的候选特征中寻找规则可以进一步拓宽它们探索问题的路径。而这种差异是否真正有益最终仍需要通过合理的验证与对照实验来判断。