数据挖掘与R语言

第17讲:集成学习——随机森林

2026年05月27日

上讲回顾

  • 回归决策树:因变量为连续型,method = "anova",叶节点输出均值
  • 分裂准则:均方误差(MSE)下降最大的特征与阈值
  • 评估指标:RMSE、R²(越小/越大越好)
  • 分类树 vs 回归树:一行代码 method 的区别,框架完全相同
  • 单棵决策树的局限:对训练数据敏感,容易过拟合;今天学习随机森林——把很多棵树"投票"结合,克服单树的缺陷。

本讲内容

  • Part 1:集成学习思想 ——三个臭皮匠为什么能顶诸葛亮?
  • Part 2:Bagging 与 Bootstrap ——随机森林的基础
  • Part 3:随机森林原理 ——双重随机性与特征随机选择
  • Part 4:关键超参数 ——ntreemtrynodesize
  • Part 5:Titanic 分类实战 ——完整 R 操作流程
  • Part 6:Boston 回归实战 ——变量重要性分析
  • Part 7:决策树 vs 随机森林 ——对比总结

Part 1:集成学习思想

三个臭皮匠,为什么能顶诸葛亮?

生活中的集成智慧

场景:你要给一套房子估价

  • 一位地产中介 → 可能有个人偏见,受当天心情影响
  • 100位地产中介,取平均值 → 偶然误差相互抵消,结果更稳定

场景:医院会诊

一位医生诊断 → 可能误诊
三位医生会诊 → 少数服从多数,误诊率大幅下降

场景:民主投票

假设每位选民做出正确判断的概率是 55%,那么 1000 人投票,多数票正确的概率远大于 55%。

提示

集成学习(Ensemble Learning)核心思想: 训练多个"弱模型",将它们的预测结果结合起来,得到比任何单个模型都更稳定、更准确的"强模型"。

为什么单棵决策树不够?

集成学习的三种主要方法

Part 2:Bagging 与 Bootstrap

随机森林的基础:有放回抽样

Bootstrap:有放回抽样

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 未被选中)

注记

关键性质:

  • 每个样本每次被抽到的概率 = 1/n
  • 平均约有 36.8% 的样本不会被任何一次抽到(称为"袋外数据 Out-of-Bag, OOB")
  • 每个 Bootstrap 样本都与原数据集大小相同,但内容不同(有重复)
  • OOB 数据可作为天然的验证集,无需额外划分!

Bootstrap 的可视化理解

Bagging:Bootstrap + 聚合

Bagging(Bootstrap Aggregating,自举聚合)

  1. 对原始训练集做 B 次 Bootstrap 抽样,得到 B 个不同的训练子集
  2. 在每个子集上独立训练一棵完整的决策树(并行,互不影响)
  3. 聚合
    • 分类:B 棵树各自投票,取多数票作为最终预测
    • 回归:B 棵树各自预测一个数值,取平均值

Part 3:随机森林原理

在 Bagging 的基础上,再加一层随机性

随机森林 = Bagging + 特征随机选择

普通 Bagging 的问题:如果有一个特别强的特征(如房价中的 sqft_living),每棵树几乎都会选它做根节点 → 各棵树高度相关 → 集成效果有限。

随机森林的解决方案:双重随机性

  1. 样本随机(Bootstrap):每棵树用不同的训练子集 ← 继承自 Bagging
  2. 特征随机:每次分裂时,只从随机选出的 \(m\) 个特征中选最优分裂点(而非全部特征)

重要

特征随机选择的效果:

  • 强制每棵树使用不同的特征组合,使各树之间的相关性降低
  • 不同的树专注于不同的特征,"从不同角度"学习数据
  • 集成后,各树的误差方向不同,相互抵消,整体更稳定

\(m\) 的经验取值:

  • 分类\(m = \sqrt{p}\)\(p\) 为总特征数)
  • 回归\(m = p/3\)

随机森林完整算法流程

随机森林 vs 单棵决策树

对比维度 单棵决策树 随机森林
训练数据 全部训练集 B 个 Bootstrap 子集(有放回)
特征选择 每次分裂用全部特征 每次分裂只用随机 \(m\) 个特征
模型数量 1 棵树 B 棵树(通常 100–1000)
预测方式 单树规则 分类:投票;回归:平均
过拟合风险 (需要剪枝) (集成效应自然抑制)
可解释性 (可视化树形图) (黑箱,无法单独解读)
计算成本 (训练 B 棵树)
预测精度 中等 通常更高
特征重要性 间接(cp 表) 直接importance()
验证集需求 需要划分测试集 OOB 误差天然验证

Part 4:关键超参数

调整随机森林的三个核心旋钮

三个最重要的超参数

重要

randomForest() 的关键参数:

参数 含义 默认值 经验推荐
ntree 树的数量 \(B\) 500 通常 500–1000 已足够;太少不稳定,太多浪费计算
mtry 每次分裂随机选取的特征数 \(m\) 分类:\(\sqrt{p}\);回归:\(p/3\) 可通过 OOB 误差调优
nodesize 叶节点最小样本数 分类:1;回归:5 增大可防止过拟合

ntree 的选择:

OOB 误差:随机森林的内置验证

提示

OOB(Out-of-Bag)误差的原理:

  • 每棵树训练时,约 36.8% 的样本未被选入(袋外样本)
  • 用这些未参与该树训练的样本来评估该树的预测误差
  • 对所有树的 OOB 误差取平均 → OOB 误差

优点: 无需额外划分验证集,计算随机森林时自动生成!

▶️ 查看代码
# OOB 误差(回归:OOB MSE 的均方根)
cat("Boston 随机森林 OOB RMSE:",
    round(sqrt(rf_reg$mse[500]), 3), "千美元\n")
Boston 随机森林 OOB RMSE: 3.39 千美元
▶️ 查看代码
# 测试集实际 RMSE
cat("测试集 RMSE:",
    round(rmse_rf, 3), "千美元\n")
测试集 RMSE: 3.452 千美元

注记

OOB 误差与测试集误差通常非常接近,是随机森林独有的"免费"验证机制。在数据量有限时尤其有价值。

Part 5:Titanic 分类实战

用随机森林预测幸存者

数据介绍与处理

▶️ 查看代码
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 类型,连续变量保持 numericfilter(!is.na(Age)) 去除缺失值是必要的——随机森林不能直接处理 NA。

步骤一:划分数据集

▶️ 查看代码
library(rsample)

set.seed(42)
split_t    <- initial_split(titanic, prop=0.7, strata="Survived")
train_t    <- training(split_t)
test_t     <- testing(split_t)


# 验证分层比例
prop.table(table(train_t$Survived)) %>% round(3)

 遇难  幸存 
0.593 0.407 

步骤二:建立随机森林分类模型

▶️ 查看代码
library(randomForest)

set.seed(42)
rf_cls <- randomForest(
  Survived ~ .,       # 公式:以所有其他变量为自变量
  data      = train_t,
  ntree     = 500,    # 树的数量
  importance = TRUE   # 计算变量重要性(必须设为 TRUE)
)

# 查看模型摘要
rf_cls

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 的变化曲线
plot(rf_cls, main="OOB 误差随树数量变化(Titanic 分类)")
legend("topright",
       legend=colnames(rf_cls$err.rate),
       fill=c("black","red","green"),
       cex=0.85)

提示

黑色线 = 整体 OOB 误差;红/绿线 = 各类别的 OOB 误差。误差曲线趋于平稳后,增加 ntree 意义不大。

步骤四:变量重要性

▶️ 查看代码
# 查看变量重要性
importance(rf_cls)
         遇难   幸存 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
▶️ 查看代码
# 可视化变量重要性
varImpPlot(rf_cls,
           main = "随机森林:变量重要性(Titanic 分类)")

▶️ 查看代码
varImp(rf_cls) %>% 
  arrange(-遇难)
         遇难   幸存
Sex    71.022 71.022
Pclass 18.954 18.954
Age    18.509 18.509
Fare   17.248 17.248
SibSp   6.886  6.886
Parch   5.202  5.202

变量重要性详解

注记

两种重要性指标:

  • MeanDecreaseAccuracy:随机打乱某变量后,OOB 准确率平均下降量 → 越大越重要
  • MeanDecreaseGini:该变量在所有分裂中贡献的 Gini 指数下降总量 → 越大越重要

步骤五:在测试集上预测与评估

▶️ 查看代码
# 预测测试集
pred_cls <- predict(rf_cls, newdata=test_t)

# 混淆矩阵
library(caret)
cm_rf <- table(pred_cls, test_t$Survived)
confusionMatrix(cm_rf, positive="幸存")
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 : 幸存          
                                        

与单棵分类树的对比

Part 6:Boston 回归实战

用随机森林预测房价

步骤一:读入数据与划分数据集

▶️ 查看代码
Boston <- read.csv("Boston.csv")

set.seed(42)
split_b  <- initial_split(Boston, prop=0.7)
train_b  <- training(split_b)
test_b   <- testing(split_b)


summary(train_b$medv)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    5.0    17.2    21.2    22.6    25.0    50.0 

提示

回归问题的随机森林不需要把因变量转换为 factormedv 保持数值型,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_caret
Random 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)
rf_reg_caret$bestTune
  mtry
2    7
▶️ 查看代码
# 查看 OOB 误差(caret 也保存了原始 randomForest 模型)
rf_reg_caret$finalModel

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
▶️ 查看代码
# 查看训练过程的性能
plot(rf_reg_caret)

注记

caret::train() 会自动调整 mtry 参数。如果不指定 tuneGrid,它会在默认的几个 mtry 值中自动选择最优值。

caret 的 train() 会输出 RMSE 和 R² 的交叉验证均值,而非 OOB 误差。原始随机森林的 OOB 指标仍在 rf_reg_caret$finalModel 中。

步骤三:在测试集上预测,计算 RMSE

▶️ 查看代码
# 预测
pred_reg_caret <- predict(rf_reg_caret, newdata = test_b)

# RMSE
rmse_rf_caret <- sqrt(mean((pred_reg_caret - test_b$medv)^2))
cat("随机森林 (caret) RMSE:$", round(rmse_rf_caret, 3), "千美元\n")
随机森林 (caret) RMSE:$ 3.308 千美元
▶️ 查看代码
# R²
ss_tot_b <- sum((test_b$medv - mean(test_b$medv))^2)
r2_rf_caret <- 1 - sum((pred_reg_caret - test_b$medv)^2) / ss_tot_b
cat("随机森林 (caret) R²:", round(r2_rf_caret, 4), "\n")
随机森林 (caret) R²: 0.8769 

步骤四:变量重要性可视化

▶️ 查看代码
# 方法一:从 caret 模型中提取 finalModel 的重要性
varImpPlot(rf_reg_caret$finalModel,
           main = "随机森林:变量重要性(Boston 房价回归)",
           cex  = 0.9)

▶️ 查看代码
# 方法二:使用 caret 的 varImp() 函数(更统一)
varImp(rf_reg_caret)
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
▶️ 查看代码
plot(varImp(rf_reg_caret))

注记

回归随机森林的重要性指标:MeanDecreaseNodePurity(即 RSS 总下降量),对应分类树的 MeanDecreaseGini。lstat(低收入比例)和 rm(平均房间数)通常是波士顿房价最重要的预测变量。

步骤五:预测效果可视化

随机森林 vs 单棵回归树:数值对比

重要

随机森林通过集成多棵树,通常能显著降低 RMSE 并提升 R²。代价是计算时间增加和可解释性降低(无法像单棵树那样直观展示决策路径,但可通过变量重要性部分弥补)。

Part 7:决策树 vs 随机森林

完整对比总结

核心对比表

对比维度 单棵决策树 随机森林
rpart randomForest
分类建模 rpart(y~., method="class") randomForest(y~., ntree=500)
回归建模 rpart(y~., method="anova") randomForest(y~., ntree=500)
训练样本 全部训练数据 Bootstrap 随机子集(有放回)
特征选择 每次分裂用全部特征 每次分裂仅用随机 \(m\) 个特征
超参数 cp(复杂度) ntreemtrynodesize
可视化 rpart.plot()(树形图) varImpPlot()(变量重要性)
过拟合控制 剪枝(prune() 集成效应自动抑制
验证方式 需要测试集 OOB 误差天然验证
预测精度 中等 通常显著更高
可解释性 (读树形图规则) (黑箱)
计算效率 较慢(训练多棵树)
变量重要性 无直接输出 importance() 直接获取
典型应用 规则可解释场景 追求精度的预测场景

何时选择哪个模型?

Part 8:你必须掌握什么?

学习路线图

完整建模流程回顾

必须掌握

重要

以下是本讲随机森林的完整核心,期末考试必考:

  1. 集成学习思想:多个弱模型结合为强模型;分类投票、回归取均值;误差相互抵消

  2. Bootstrap:有放回抽样;约 36.8% 未被选中的样本为 OOB 数据;OOB 误差是天然验证

  3. 随机森林双重随机性:样本随机(Bootstrap)+ 特征随机(每次分裂只用 \(m\) 个特征);目的是降低树间相关性

  4. R 操作randomForest(y~., data, ntree=500, importance=TRUE);分类/回归自动判断;不需要 method 参数

  5. OOB 误差rf$mse(回归)或 rf$err.rate(分类);print(rf) 直接查看

  6. 变量重要性importance(rf) 获取数值;varImpPlot(rf) 可视化;分类用 MeanDecreaseAccuracy,回归用 MeanDecreaseNodePurity

  7. 预测predict(rf, newdata=test) 直接输出(分类输出因子,回归输出数值)

  8. 决策树 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%数据进行模型验证,分析模型预测的准确性。

9.1

读入数据文件,将数据集进行划分,70%为训练数据集,30%为测试数据集,见参考代码。查看训练数据集和测试数据集的结构信息。并分析训练数据集的结构信息。

▶️ 查看代码
# 1.1 读入数据(R内置数据集)
data(iris)

# 查看数据结构
str(iris)
'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 ...
▶️ 查看代码
# 1.2 划分训练集和测试集(70% / 30%)
split <- initial_split(iris, prop = 0.7, strata = Species)
train_data <- training(split)
test_data  <- testing(split)

# 1.3 查看划分结果
cat("训练集样本数:", nrow(train_data), "\n")
训练集样本数: 105 
▶️ 查看代码
cat("测试集样本数:", nrow(test_data), "\n")
测试集样本数: 45 
▶️ 查看代码
# 1.4 分析训练集结构
str(train_data)
'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 ...
▶️ 查看代码
summary(train_data)
  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                  
▶️ 查看代码
# 查看各类别分布
table(train_data$Species)

    setosa versicolor  virginica 
        35         35         35 

9.2

用训练数据集运用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.
▶️ 查看代码
# 2.4 分析不同 mtry 组合下的平均分类准确率
plot(rfModel)

▶️ 查看代码
# 查看最佳 mtry 值
rfModel$bestTune
  mtry
2    3

9.3

将模型rfModel,应用于测试数据集testset,通过CrossTable函数来分析模型的预测准确率。

▶️ 查看代码
library(gmodels)

# 3.1 对测试集进行预测
pred_class <- predict(rfModel, newdata = test_data)

# 3.2 用 CrossTable 生成混淆矩阵
CrossTable(
  test_data$Species,
  pred_class,
  prop.chisq = FALSE,
  prop.r = FALSE,
  prop.c = TRUE,
  prop.t = TRUE,
  dnn = c("实际类别", "预测类别")
)

 
   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 |            | 
-------------|------------|------------|------------|------------|

 
▶️ 查看代码
# 3.3 计算准确率
accuracy_caret <- mean(pred_class == test_data$Species)
cat("模型准确率(caret):", round(accuracy_caret, 4), "\n")
模型准确率(caret): 0.9556 

9.4

用训练数据集运用randomForest函数进行随机森林建模,设置随机数种子1000,以Species为因变量;查看模型信息,并分析模型的错误率。

▶️ 查看代码
library(randomForest)

# 4.1 设置随机种子
set.seed(1000)

# 4.2 训练随机森林模型
rf_raw <- randomForest(
  Species ~ .,
  data = train_data,
  ntree = 500,
  importance = TRUE
)

# 4.3 查看模型信息
print(rf_raw)

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
▶️ 查看代码
# 4.4 分析模型的错误率
# 整体 OOB 错误率
cat("OOB 错误率:", round(rf_raw$err.rate[nrow(rf_raw$err.rate), "OOB"], 4), "\n")
OOB 错误率: 0.0381 
▶️ 查看代码
# 各类别的 class.error
rf_raw$confusion
           setosa versicolor virginica class.error
setosa         35          0         0     0.00000
versicolor      0         33         2     0.05714
virginica       0          2        33     0.05714

9.5

对随机森林结果可视化,并分析建立多少树的时候模型预测的分类结果趋于稳定。

▶️ 查看代码
# 5.1 绘制错误率随树数量变化的曲线
plot(rf_raw, main = "随机森林错误率 vs 树的数量")

▶️ 查看代码
# 5.2 分析:观察曲线何时趋于稳定
# 从图中可以看出,大约在 100 棵树之后错误率基本稳定

6、将模型应用于测试数据集,并分析模型预测准确性:模型准确率、精准度、召回率。

▶️ 查看代码
# 6.1 预测
pred_raw <- predict(rf_raw, newdata = test_data)

# 6.2 生成混淆矩阵
conf_matrix <- table(实际 = test_data$Species, 预测 = pred_raw)

confusionMatrix(conf_matrix)
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、对各个自变量进行重要程度度量,并按照变量重要程度降序排列。

▶️ 查看代码
# 7.1 查看变量重要性数值
importance(rf_raw)
             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
▶️ 查看代码
# 7.2 可视化变量重要性
varImpPlot(rf_raw, main = "鸢尾花分类:变量重要性")

谢谢!

第17讲:集成学习——随机森林


「一棵树可能倒下,但一片森林屹立不倒——随机森林的智慧,在于让每棵树都不完美,却让整体无比稳健。」