随机森林回归(优先)
一、直观理解:很多棵“各看一部分”的树,投票出结果
随机森林(Random Forest)是集成方法:并行训练大量回归树,每棵树只看到自助抽样的样本,并在分裂时随机参考部分特征,最后把各树预测平均:
单棵树又脆又容易过拟合;一群“去相关”的树平均后,方差下降,通常更稳。对表格型中小数据、存在非线性与变量交互的建模题,随机森林应作为机器学习侧的优先基线,往往先于 SVM 调参地狱与提升树的精细战。
它不自动处理时间依赖:若是时间序列,必须构造滞后特征,并按时间切分,不能随机打乱。
二、适用场景与优缺点
| 类型 | 说明 |
|---|---|
| 适用场景 | 表格特征;非线性/交互; 从数百到数万;需要变量重要性;缺失与量纲问题相对不敏感;竞赛中要强力黑箱基线。 |
| 核心优点 | 默认超参往往就可用;抗过拟合相对好;能处理混合类型(经编码);提供 OOB 误差与重要性;实现成熟(fitrensemble)。 |
| 局限与缺点 | 外推弱(树在训练域内分段常数);趋势外推不如机理/时序模型;解释性不如线性系数;高基数类别需处理;纯噪声特征多时重要性会骗人。 |
三、核心原理
1. 回归树
递归选择特征与阈值,使子节点响应方差下降最大,直到深度/叶样本约束。叶节点输出训练样本均值。
2. Bagging + 特征随机
- Bootstrap 样本 → 树之间样本扰动;
- 每次分裂只随机看 个特征 → 进一步降相关。
平均后方差减小,偏差略升,但总体测试误差常改善。
3. OOB 误差
未抽入某棵树的样本可做袋外预测,近似交叉验证,便于快速调参。但仍建议保留真正的测试集或时间外推集。
四、特征、划分与调参
- 时间序列:构造 ,日历特征,严格时间切分;
- 截面:
cvpartitionK 折; - 类别特征:哑变量或分类树原生处理;
- 主要超参:树棵数
NumLearningCycles、最小叶MinLeafSize、最大分裂、NumVariablesToSample; - 先粗后细;以验证/OOB/测试 RMSE 为准,而不是训练 ;
- 与线性回归、PLS、单棵树对比,证明集成增益。
五、MATLAB 示例
%% 随机森林回归:截面示例 + 时间滞后示例要点
rng(19);
n = 500; p = 8;
X = randn(n,p);
y = 1.5*X(:,1) + 0.8*X(:,2).^2 + 0.5*X(:,1).*X(:,3) + 0.7*randn(n,1);
Ytbl = array2table([X y], "VariableNames", ...
[compose("x%d",1:p), "y"]);
% 划分:这里用 holdout;若是时间数据请改为前 T0 / 后测试
cv = cvpartition(n, "HoldOut", 0.25);
tr = training(cv); te = test(cv);
% Bag 决策树 = 随机森林风格
t = templateTree("MinLeafSize",5, "NumVariablesToSample","all");
Mdl = fitrensemble(Ytbl(tr,:), "y", ...
"Method","Bag", ...
"NumLearningCycles",200, ...
"Learners",t, ...
"OOBPrediction","on");
yhat = predict(Mdl, Ytbl(te,:));
rmse = sqrt(mean((Ytbl.y(te)-yhat).^2));
fprintf("测试 RMSE=%.4f\n", rmse);
% OOB 误差曲线
figure; plot(oobError(Mdl)); xlabel("树的棵数"); ylabel("OOB MSE");
title("OOB 误差随树数变化");
% 与线性回归对比
mdlLM = fitlm(Ytbl(tr,:), "y ~ x1+x2+x3+x4+x5+x6+x7+x8");
yLM = predict(mdlLM, Ytbl(te,:));
rmseLM = sqrt(mean((Ytbl.y(te)-yLM).^2));
fprintf("线性 RMSE=%.4f\n", rmseLM);
% 置换重要性(更稳妥的重要性)
imp = oobPermutedPredictorImportance(Mdl);
figure; bar(imp);
set(gca,"XTickLabel",Mdl.PredictorNames,"XTickLabelRotation",45);
ylabel("OOB 置换重要性"); title("变量重要性");
%% 时间序列用法提示(伪代码)
% ylag1 = [nan; y(1:end-1)];
% ylag2 = [nan; nan; y(1:end-2)];
% T0 = ...; 只用 1:T0 训练,T0+1:end 测试
% 禁止 cvpartition 随机打乱时间行
大规模或需要更强非线性时,再考虑 LSBoost/fitrensemble 提升或 Python XGBoost;多数中小数据题随机森林已经足够。
六、如何解释结果
报告:
- 特征工程列表(尤其是滞后与编码);
- 划分协议(时间/ K 折);
- 超参与树棵数、OOB 曲线是否收敛;
- 测试 RMSE/MAE,对比线性与单棵树;
- 变量重要性(置换重要性优先于简单分裂计数);
- 部分依赖图(
plotPartialDependence)看方向; - 局限:训练域外不能乱外推;相关特征会分摊重要性。
七、常见误区
1. 时间序列随机 K 折
未来泄漏,分数虚高。
2. 只报训练
树模型极易贴合训练,必须看 OOB/测试。
3. 用 RF 外推从未见过的时间趋势
树不能自然外推直线趋势,应先差分/去势或加时间强特征并谨慎验证。
4. 把重要性当因果排序
相关特征、编码方式都会扭曲重要性。
5. 无意义地堆几千棵树
OOB 收敛后收益很小,徒增时间。
八、小结
随机森林回归的核心是:
通过自助抽样与随机特征分裂训练多棵去相关树,并平均预测,以在表格数据上获得稳健的非线性基线。
在建模竞赛的机器学习选项里,它应优先尝试:调参成本低、表现常不差、解释工具够用。MATLAB 用 fitrensemble(...,'Method','Bag') 即可。
实操清单:
- 先做线性回归/时序基线;
- 再上 RF,报告测试 RMSE 增量;
- 用置换重要性与部分依赖写解释;
- 仍不足且数据很大时,才考虑提升树。
最终仍以训练期外误差与基线对比为准,不要只看 。需要更强拟合或超大数据时,再考虑提升树家族。