第17讲:集成学习——随机森林
2026年05月27日
method = "anova",叶节点输出均值
method 的区别,框架完全相同ntree、mtry、nodesize
三个臭皮匠,为什么能顶诸葛亮?
场景:你要给一套房子估价
场景:医院会诊
一位医生诊断 → 可能误诊
三位医生会诊 → 少数服从多数,误诊率大幅下降
场景:民主投票
假设每位选民做出正确判断的概率是 55%,那么 1000 人投票,多数票正确的概率远大于 55%。
提示
集成学习(Ensemble Learning)核心思想: 训练多个"弱模型",将它们的预测结果结合起来,得到比任何单个模型都更稳定、更准确的"强模型"。
随机森林的基础:有放回抽样
Bootstrap(自举法):从原始数据中有放回地随机抽取与原数据集相同大小的样本。
例:原始数据有 5 个样本 {A, B, C, D, E}
| Bootstrap 第1次 | Bootstrap 第2次 | Bootstrap 第3次 |
|---|---|---|
| A, A, C, D, B | B, C, C, E, A | D, A, B, B, D |
| (B、E 未被选中) | (D 未被选中) | (C、E 未被选中) |
注记
关键性质:
Bagging(Bootstrap Aggregating,自举聚合):
在 Bagging 的基础上,再加一层随机性
普通 Bagging 的问题:如果有一个特别强的特征(如房价中的 sqft_living),每棵树几乎都会选它做根节点 → 各棵树高度相关 → 集成效果有限。
随机森林的解决方案:双重随机性
重要
特征随机选择的效果:
\(m\) 的经验取值:
| 对比维度 | 单棵决策树 | 随机森林 |
|---|---|---|
| 训练数据 | 全部训练集 | B 个 Bootstrap 子集(有放回) |
| 特征选择 | 每次分裂用全部特征 | 每次分裂只用随机 \(m\) 个特征 |
| 模型数量 | 1 棵树 | B 棵树(通常 100–1000) |
| 预测方式 | 单树规则 | 分类:投票;回归:平均 |
| 过拟合风险 | 高(需要剪枝) | 低(集成效应自然抑制) |
| 可解释性 | 高(可视化树形图) | 低(黑箱,无法单独解读) |
| 计算成本 | 低 | 高(训练 B 棵树) |
| 预测精度 | 中等 | 通常更高 |
| 特征重要性 | 间接(cp 表) |
直接(importance()) |
| 验证集需求 | 需要划分测试集 | OOB 误差天然验证 |
调整随机森林的三个核心旋钮
重要
randomForest() 的关键参数:
| 参数 | 含义 | 默认值 | 经验推荐 |
|---|---|---|---|
ntree |
树的数量 \(B\) | 500 | 通常 500–1000 已足够;太少不稳定,太多浪费计算 |
mtry |
每次分裂随机选取的特征数 \(m\) | 分类:\(\sqrt{p}\);回归:\(p/3\) | 可通过 OOB 误差调优 |
nodesize |
叶节点最小样本数 | 分类:1;回归:5 | 增大可防止过拟合 |
提示
OOB(Out-of-Bag)误差的原理:
优点: 无需额外划分验证集,计算随机森林时自动生成!
注记
OOB 误差与测试集误差通常非常接近,是随机森林独有的"免费"验证机制。在数据量有限时尤其有价值。
用随机森林预测幸存者
library(dplyr)
library(randomForest)
titanic_raw <- read.csv("titanic.csv")
titanic <- titanic_raw %>%
select(Survived, Pclass, Sex, Age, Fare, SibSp, Parch) %>%
mutate(
Survived = factor(Survived, levels=c(0,1), labels=c("遇难","幸存")),
Pclass = factor(Pclass),
Sex = factor(Sex)
) %>%
filter(!is.na(Age))
str(titanic)'data.frame': 714 obs. of 7 variables:
$ Survived: Factor w/ 2 levels "遇难","幸存": 1 2 2 2 1 1 1 2 2 2 ...
$ Pclass : Factor w/ 3 levels "1","2","3": 3 1 3 1 3 1 3 3 2 3 ...
$ Sex : Factor w/ 2 levels "female","male": 2 1 1 1 2 2 2 1 1 1 ...
$ Age : num 22 38 26 35 35 54 2 27 14 4 ...
$ Fare : num 7.25 71.28 7.92 53.1 8.05 ...
$ SibSp : int 1 1 0 1 0 0 3 0 1 1 ...
$ Parch : int 0 0 0 0 0 0 1 2 0 1 ...
注记
randomForest() 要求因子变量必须已经是 factor 类型,连续变量保持 numeric。filter(!is.na(Age)) 去除缺失值是必要的——随机森林不能直接处理 NA。
Call:
randomForest(formula = Survived ~ ., data = train_t, ntree = 500, importance = TRUE)
Type of random forest: classification
Number of trees: 500
No. of variables tried at each split: 2
OOB estimate of error rate: 17.23%
Confusion matrix:
遇难 幸存 class.error
遇难 265 31 0.1047
幸存 55 148 0.2709
注记
输出中的 OOB estimate of error rate 就是 OOB 误差——无需测试集即可初步评估模型。Confusion matrix 是基于 OOB 样本的混淆矩阵。
提示
黑色线 = 整体 OOB 误差;红/绿线 = 各类别的 OOB 误差。误差曲线趋于平稳后,增加 ntree 意义不大。
遇难 幸存 MeanDecreaseAccuracy MeanDecreaseGini
Pclass 16.055 21.853 27.786 17.12
Sex 67.989 74.054 85.141 70.11
Age 19.289 17.728 26.659 39.32
Fare 16.248 18.248 25.317 42.21
SibSp 11.477 2.295 11.690 9.24
Parch 7.714 2.690 8.773 8.53
注记
两种重要性指标:
Confusion Matrix and Statistics
pred_cls 遇难 幸存
遇难 108 30
幸存 20 57
Accuracy : 0.767
95% CI : (0.705, 0.822)
No Information Rate : 0.595
P-Value [Acc > NIR] : 7.73e-08
Kappa : 0.508
Mcnemar's Test P-Value : 0.203
Sensitivity : 0.655
Specificity : 0.844
Pos Pred Value : 0.740
Neg Pred Value : 0.783
Prevalence : 0.405
Detection Rate : 0.265
Detection Prevalence : 0.358
Balanced Accuracy : 0.749
'Positive' Class : 幸存
用随机森林预测房价
Min. 1st Qu. Median Mean 3rd Qu. Max.
5.0 17.2 21.2 22.6 25.0 50.0
提示
回归问题的随机森林不需要把因变量转换为 factor。medv 保持数值型,randomForest() 会自动判断这是回归任务(type = "regression")。
library(caret)
library(randomForest)
# 设置交叉验证参数(可选,但推荐)
set.seed(42)
ctrl <- trainControl(
method = "repeatedcv", # 重复交叉验证
number = 5, # 5 折
repeats = 2 # 重复 2 次
)
set.seed(42)
rf_reg_caret <- train(
medv ~ .,
data = train_b,
method = "rf", # 随机森林
trControl = ctrl,
ntree = 500,
importance = TRUE,
verbose = FALSE
)
# 查看结果
rf_reg_caretRandom Forest
354 samples
13 predictor
No pre-processing
Resampling: Cross-Validated (5 fold, repeated 2 times)
Summary of sample sizes: 284, 283, 282, 284, 283, 282, ...
Resampling results across tuning parameters:
mtry RMSE Rsquared MAE
2 4.027 0.8312 2.635
7 3.575 0.8536 2.357
13 3.782 0.8305 2.428
RMSE was used to select the optimal model using the smallest value.
The final value used for the model was mtry = 7.
mtry
2 7
Call:
randomForest(x = x, y = y, ntree = 500, mtry = param$mtry, importance = TRUE, verbose = FALSE)
Type of random forest: regression
Number of trees: 500
No. of variables tried at each split: 7
Mean of squared residuals: 11.52
% Var explained: 86.03
注记
caret::train() 会自动调整 mtry 参数。如果不指定 tuneGrid,它会在默认的几个 mtry 值中自动选择最优值。
caret 的 train() 会输出 RMSE 和 R² 的交叉验证均值,而非 OOB 误差。原始随机森林的 OOB 指标仍在 rf_reg_caret$finalModel 中。
随机森林 (caret) RMSE:$ 3.308 千美元
随机森林 (caret) R²: 0.8769
rf variable importance
Overall
rm 100.000
lstat 77.999
dis 39.315
nox 39.065
ptratio 29.637
crim 28.263
age 26.896
tax 18.004
indus 16.642
black 15.442
rad 9.186
zn 0.209
chas 0.000
注记
回归随机森林的重要性指标:MeanDecreaseNodePurity(即 RSS 总下降量),对应分类树的 MeanDecreaseGini。lstat(低收入比例)和 rm(平均房间数)通常是波士顿房价最重要的预测变量。
重要
随机森林通过集成多棵树,通常能显著降低 RMSE 并提升 R²。代价是计算时间增加和可解释性降低(无法像单棵树那样直观展示决策路径,但可通过变量重要性部分弥补)。
完整对比总结
| 对比维度 | 单棵决策树 | 随机森林 |
|---|---|---|
| 包 | rpart |
randomForest |
| 分类建模 | rpart(y~., method="class") |
randomForest(y~., ntree=500) |
| 回归建模 | rpart(y~., method="anova") |
randomForest(y~., ntree=500) |
| 训练样本 | 全部训练数据 | Bootstrap 随机子集(有放回) |
| 特征选择 | 每次分裂用全部特征 | 每次分裂仅用随机 \(m\) 个特征 |
| 超参数 |
cp(复杂度) |
ntree、mtry、nodesize
|
| 可视化 |
rpart.plot()(树形图) |
varImpPlot()(变量重要性) |
| 过拟合控制 | 剪枝(prune()) |
集成效应自动抑制 |
| 验证方式 | 需要测试集 | OOB 误差天然验证 |
| 预测精度 | 中等 | 通常显著更高 |
| 可解释性 | 高(读树形图规则) | 低(黑箱) |
| 计算效率 | 快 | 较慢(训练多棵树) |
| 变量重要性 | 无直接输出 |
importance() 直接获取 |
| 典型应用 | 规则可解释场景 | 追求精度的预测场景 |
学习路线图
重要
以下是本讲随机森林的完整核心,期末考试必考:
集成学习思想:多个弱模型结合为强模型;分类投票、回归取均值;误差相互抵消
Bootstrap:有放回抽样;约 36.8% 未被选中的样本为 OOB 数据;OOB 误差是天然验证
随机森林双重随机性:样本随机(Bootstrap)+ 特征随机(每次分裂只用 \(m\) 个特征);目的是降低树间相关性
R 操作:randomForest(y~., data, ntree=500, importance=TRUE);分类/回归自动判断;不需要 method 参数
OOB 误差:rf$mse(回归)或 rf$err.rate(分类);print(rf) 直接查看
变量重要性:importance(rf) 获取数值;varImpPlot(rf) 可视化;分类用 MeanDecreaseAccuracy,回归用 MeanDecreaseNodePurity
预测:predict(rf, newdata=test) 直接输出(分类输出因子,回归输出数值)
决策树 vs 随机森林:精度更高但可解释性更低;会在两者间根据场景做选择
警告
请对照检查:
| 错误 | 正确做法 |
|---|---|
randomForest() 里写 method="class"
|
不需要 method 参数;因变量是 factor → 自动分类,是 numeric → 自动回归 |
| 因变量忘记转为 factor(分类任务) | 建模前必须 mutate(y = factor(y));否则会被当作回归处理 |
不设 importance=TRUE
|
不设则无法调用 importance() 和 varImpPlot();建议始终设为 TRUE
|
| 数据含 NA 不处理 |
randomForest 不能处理 NA;建模前必须 drop_na() 或填补缺失值 |
| ntree 设得太小(如 10) | OOB 误差不稳定;通常至少 200,推荐 500 |
| 把 OOB 误差当测试集误差 | OOB 是训练过程中的内置验证,仍需在独立测试集上做最终评估 |
| 认为随机森林一定比决策树好 | 数据量小或需要可解释性时,单棵决策树可能是更好的选择 |
集成思想:多棵树的预测结合(投票/平均),误差相互抵消,整体比单树更稳定
双重随机性:Bootstrap 样本随机 + 每次分裂特征随机 → 降低树间相关性 → 集成效果更好
OOB 误差:约 36.8% 的袋外样本天然构成验证集,无需额外划分;print(rf) 直接查看
变量重要性:随机森林的独特优势;varImpPlot() 一行可视化,直观识别最重要的预测变量
vs 决策树:随机森林精度更高,但可解释性更低、计算更慢;实战中两者互补使用
项目介绍: 项目介绍:现有鸢尾花数据集iris(R内置数据集),需要通过鸢尾花的花瓣长度、宽度、花萼长度和宽度四个属性信息,建立关于鸢尾花类型Species的随机森林模型。将70%数据进行模型训练,30%数据进行模型验证,分析模型预测的准确性。
读入数据文件,将数据集进行划分,70%为训练数据集,30%为测试数据集,见参考代码。查看训练数据集和测试数据集的结构信息。并分析训练数据集的结构信息。
'data.frame': 150 obs. of 5 variables:
$ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
$ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
$ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
$ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
$ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
训练集样本数: 105
测试集样本数: 45
'data.frame': 105 obs. of 5 variables:
$ Sepal.Length: num 4.9 4.7 4.6 5 5.4 4.9 5.4 4.3 5.7 5.4 ...
$ Sepal.Width : num 3 3.2 3.1 3.6 3.9 3.1 3.7 3 4.4 3.9 ...
$ Petal.Length: num 1.4 1.3 1.5 1.4 1.7 1.5 1.5 1.1 1.5 1.3 ...
$ Petal.Width : num 0.2 0.2 0.2 0.2 0.4 0.1 0.2 0.1 0.4 0.4 ...
$ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
Min. :4.30 Min. :2.20 Min. :1.00 Min. :0.1 setosa :35
1st Qu.:5.20 1st Qu.:2.80 1st Qu.:1.50 1st Qu.:0.3 versicolor:35
Median :5.70 Median :3.00 Median :4.20 Median :1.3 virginica :35
Mean :5.84 Mean :3.07 Mean :3.76 Mean :1.2
3rd Qu.:6.30 3rd Qu.:3.40 3rd Qu.:5.10 3rd Qu.:1.8
Max. :7.90 Max. :4.40 Max. :6.90 Max. :2.5
setosa versicolor virginica
35 35 35
用训练数据集运用train函数进行随机森林建模,得到模型结果为rfModel,定义采样方法为repeatedcv,5折交叉验证,迭代5次。随机数种子为1000次。因变量为Species ,其余变量为自变量。分析随机森林的特征选择不同组合下的平均分类准确率。
# 2.1 设置交叉验证参数
set.seed(1000)
ctrl <- trainControl(
method = "repeatedcv", # 重复交叉验证
number = 5, # 5 折
repeats = 5 # 迭代 5 次
)
# 2.2 训练随机森林模型
rfModel <- train(
Species ~ .,
data = train_data,
method = "rf",
trControl = ctrl,
importance = TRUE,
ntree = 500,
verbose = FALSE
)
# 2.3 查看模型结果
print(rfModel)Random Forest
105 samples
4 predictor
3 classes: 'setosa', 'versicolor', 'virginica'
No pre-processing
Resampling: Cross-Validated (5 fold, repeated 5 times)
Summary of sample sizes: 84, 84, 84, 84, 84, 84, ...
Resampling results across tuning parameters:
mtry Accuracy Kappa
2 0.9562 0.9343
3 0.9600 0.9400
4 0.9581 0.9371
Accuracy was used to select the optimal model using the largest value.
The final value used for the model was mtry = 3.
mtry
2 3
将模型rfModel,应用于测试数据集testset,通过CrossTable函数来分析模型的预测准确率。
Cell Contents
|-------------------------|
| N |
| N / Col Total |
| N / Table Total |
|-------------------------|
Total Observations in Table: 45
| 预测类别
实际类别 | setosa | versicolor | virginica | Row Total |
-------------|------------|------------|------------|------------|
setosa | 15 | 0 | 0 | 15 |
| 1.000 | 0.000 | 0.000 | |
| 0.333 | 0.000 | 0.000 | |
-------------|------------|------------|------------|------------|
versicolor | 0 | 15 | 0 | 15 |
| 0.000 | 0.882 | 0.000 | |
| 0.000 | 0.333 | 0.000 | |
-------------|------------|------------|------------|------------|
virginica | 0 | 2 | 13 | 15 |
| 0.000 | 0.118 | 1.000 | |
| 0.000 | 0.044 | 0.289 | |
-------------|------------|------------|------------|------------|
Column Total | 15 | 17 | 13 | 45 |
| 0.333 | 0.378 | 0.289 | |
-------------|------------|------------|------------|------------|
模型准确率(caret): 0.9556
用训练数据集运用randomForest函数进行随机森林建模,设置随机数种子1000,以Species为因变量;查看模型信息,并分析模型的错误率。
Call:
randomForest(formula = Species ~ ., data = train_data, ntree = 500, importance = TRUE)
Type of random forest: classification
Number of trees: 500
No. of variables tried at each split: 2
OOB estimate of error rate: 3.81%
Confusion matrix:
setosa versicolor virginica class.error
setosa 35 0 0 0.00000
versicolor 0 33 2 0.05714
virginica 0 2 33 0.05714
OOB 错误率: 0.0381
setosa versicolor virginica class.error
setosa 35 0 0 0.00000
versicolor 0 33 2 0.05714
virginica 0 2 33 0.05714
对随机森林结果可视化,并分析建立多少树的时候模型预测的分类结果趋于稳定。
6、将模型应用于测试数据集,并分析模型预测准确性:模型准确率、精准度、召回率。
Confusion Matrix and Statistics
预测
实际 setosa versicolor virginica
setosa 15 0 0
versicolor 0 15 0
virginica 0 2 13
Overall Statistics
Accuracy : 0.956
95% CI : (0.849, 0.995)
No Information Rate : 0.378
P-Value [Acc > NIR] : 2.61e-16
Kappa : 0.933
Mcnemar's Test P-Value : NA
Statistics by Class:
Class: setosa Class: versicolor Class: virginica
Sensitivity 1.000 0.882 1.000
Specificity 1.000 1.000 0.938
Pos Pred Value 1.000 1.000 0.867
Neg Pred Value 1.000 0.933 1.000
Prevalence 0.333 0.378 0.289
Detection Rate 0.333 0.333 0.289
Detection Prevalence 0.333 0.333 0.333
Balanced Accuracy 1.000 0.941 0.969
7、对各个自变量进行重要程度度量,并按照变量重要程度降序排列。
setosa versicolor virginica MeanDecreaseAccuracy MeanDecreaseGini
Sepal.Length 6.263 0.5197 10.20 9.931 7.004
Sepal.Width 4.836 1.2470 2.88 4.631 1.448
Petal.Length 23.430 30.7303 26.12 33.518 30.075
Petal.Width 20.642 29.2989 29.17 32.502 30.707
第17讲:集成学习——随机森林
「一棵树可能倒下,但一片森林屹立不倒——随机森林的智慧,在于让每棵树都不完美,却让整体无比稳健。」
数据挖掘与R语言 | 集成学习:随机森林