跳到主要内容

随机森林回归(优先)

一、直观理解:很多棵“各看一部分”的树,投票出结果​

随机森林(Random Forest)是集成方法:并行训练大量回归树,每棵树只看到自助抽样的样本,并在分裂时随机参考部分特征,最后把各树预测平均:

y^(x)=1B∑b=1BTb(x)\hat y(x)=\frac{1}{B}\sum_{b=1}^{B} T_b(x)

单棵树又脆又容易过拟合;一群“去相关”的树平均后,方差下降,通常更稳。对表格型中小数据、存在非线性与变量交互的建模题,随机森林应作为机器学习侧的优先基线,往往先于 SVM 调参地狱与提升树的精细战。

它不自动处理时间依赖:若是时间序列,必须构造滞后特征,并按时间切分,不能随机打乱。

二、适用场景与优缺点​

类型说明
适用场景表格特征;非线性/交互;nn 从数百到数万;需要变量重要性;缺失与量纲问题相对不敏感;竞赛中要强力黑箱基线。
核心优点默认超参往往就可用;抗过拟合相对好;能处理混合类型(经编码);提供 OOB 误差与重要性;实现成熟(fitrensemble)。
局限与缺点外推弱(树在训练域内分段常数);趋势外推不如机理/时序模型;解释性不如线性系数;高基数类别需处理;纯噪声特征多时重要性会骗人。

三、核心原理​

1. 回归树​

递归选择特征与阈值,使子节点响应方差下降最大,直到深度/叶样本约束。叶节点输出训练样本均值。

2. Bagging + 特征随机​

  • Bootstrap 样本 → 树之间样本扰动;
  • 每次分裂只随机看 mm 个特征 → 进一步降相关。

平均后方差减小,偏差略升,但总体测试误差常改善。

3. OOB 误差​

未抽入某棵树的样本可做袋外预测,近似交叉验证,便于快速调参。但仍建议保留真正的测试集或时间外推集。

四、特征、划分与调参​

  1. 时间序列:构造 yt−1,…y_{t-1},\ldots,日历特征,严格时间切分;
  2. 截面:cvpartition K 折;
  3. 类别特征:哑变量或分类树原生处理;
  4. 主要超参:树棵数 NumLearningCycles、最小叶 MinLeafSize、最大分裂、NumVariablesToSample;
  5. 先粗后细;以验证/OOB/测试 RMSE 为准,而不是训练 R2R^2;
  6. 与线性回归、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;多数中小数据题随机森林已经足够。

六、如何解释结果​

报告:

  1. 特征工程列表(尤其是滞后与编码);
  2. 划分协议(时间/ K 折);
  3. 超参与树棵数、OOB 曲线是否收敛;
  4. 测试 RMSE/MAE,对比线性与单棵树;
  5. 变量重要性(置换重要性优先于简单分裂计数);
  6. 部分依赖图(plotPartialDependence)看方向;
  7. 局限:训练域外不能乱外推;相关特征会分摊重要性。

七、常见误区​

1. 时间序列随机 K 折​

未来泄漏,分数虚高。

2. 只报训练 R2≈1R^2\approx 1​

树模型极易贴合训练,必须看 OOB/测试。

3. 用 RF 外推从未见过的时间趋势​

树不能自然外推直线趋势,应先差分/去势或加时间强特征并谨慎验证。

4. 把重要性当因果排序​

相关特征、编码方式都会扭曲重要性。

5. 无意义地堆几千棵树​

OOB 收敛后收益很小,徒增时间。

八、小结​

随机森林回归的核心是:

通过自助抽样与随机特征分裂训练多棵去相关树,并平均预测,以在表格数据上获得稳健的非线性基线。

在建模竞赛的机器学习选项里,它应优先尝试:调参成本低、表现常不差、解释工具够用。MATLAB 用 fitrensemble(...,'Method','Bag') 即可。

实操清单:

  1. 先做线性回归/时序基线;
  2. 再上 RF,报告测试 RMSE 增量;
  3. 用置换重要性与部分依赖写解释;
  4. 仍不足且数据很大时,才考虑提升树。

最终仍以训练期外误差与基线对比为准,不要只看 R2R^2。需要更强拟合或超大数据时,再考虑提升树家族。