数学建模国赛倒计时 1 天 ——《机器学习精讲(决策树R语言实战篇)》

文章目录

0、引言

距离比赛还有最后 1 天。理论篇讲清楚了"为什么用"和"怎么解释",这一篇直接上手。用 iris 数据集,完整可运行,跑完就能画出决策树、计算准确率、提取分类规则、写出论文表格。


一、为什么用 iris 数据集?

数据集 特点 为什么适合演示决策树
iris R 自带,150 行,5 个变量 经典分类数据集,不包含缺失值,3 个类别
目标 根据花萼/花瓣尺寸预测鸢尾花种类 分类树 + 多分类,覆盖国赛常见场景

二、第一步:加载数据并查看结构

2.1 加载数据

r 复制代码
# 加载数据
data("iris")
df <- iris

# 查看数据结构和前几行
str(df)
head(df)

输出:

复制代码
'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.3 ...
 $ 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","virginica": 1 1 1 1 1 1 1 1 1 1 ...

关键信息

  • 4 个数值型自变量,1 个分类因变量(3 个类别)
  • 没有任何缺失值,直接可用

三、第二步:划分训练集和测试集

r 复制代码
# 设置随机种子(保证结果可重复)
set.seed(123)

# 随机抽取 70% 作为训练集
train_index <- sample(1:nrow(df), size = 0.7 * nrow(df))
train_data <- df[train_index, ]
test_data <- df[-train_index, ]

cat("训练集样本数:", nrow(train_data), "\n")
cat("测试集样本数:", nrow(test_data), "\n")

运行结果:

复制代码
训练集样本数: 105 
测试集样本数: 45 

四、第三步:建立决策树模型

4.1 加载 rpart 包并建树

r 复制代码
# 安装并加载 rpart 包(如果没装)
# install.packages("rpart")
library(rpart)

# 建决策树(Species ~ 所有变量)
tree_model <- rpart(Species ~ ., 
                    data = train_data, 
                    method = "class",      # 分类问题
                    control = rpart.control(
                      minsplit = 5,        # 节点最小样本数
                      minbucket = 3,       # 叶子最小样本数
                      maxdepth = 5,        # 最大深度
                      cp = 0.01            # 复杂度参数
                    ))

# 查看模型摘要
summary(tree_model)
Call:
rpart(formula = Species ~ ., data = train_data, method = "class", 
    control = rpart.control(minsplit = 5, minbucket = 3, maxdepth = 5, 
        cp = 0.01))
  n= 105 

          CP nsplit  rel error    xerror       xstd
1 0.52941176      0 1.00000000 1.2058824 0.06232572
2 0.39705882      1 0.47058824 0.5441176 0.07198662
3 0.02941176      2 0.07352941 0.1176471 0.03997857
4 0.01000000      3 0.04411765 0.1176471 0.03997857

Variable importance
 Petal.Width Petal.Length Sepal.Length  Sepal.Width 
          33           33           21           13 

Node number 1: 105 observations,    complexity param=0.5294118
  predicted class=virginica   expected loss=0.647619  P(node) =1
    class counts:    36    32    37
   probabilities: 0.343 0.305 0.352 
  left son=2 (36 obs) right son=3 (69 obs)
  Primary splits:
      Petal.Length < 2.45 to the left,  improve=35.54783, (0 missing)
      Petal.Width  < 0.8  to the left,  improve=35.54783, (0 missing)
      Sepal.Length < 5.45 to the left,  improve=24.79179, (0 missing)
      Sepal.Width  < 3.25 to the right, improve=12.34670, (0 missing)
  Surrogate splits:
      Petal.Width  < 0.8  to the left,  agree=1.000, adj=1.000, (0 split)
      Sepal.Length < 5.45 to the left,  agree=0.924, adj=0.778, (0 split)
      Sepal.Width  < 3.25 to the right, agree=0.819, adj=0.472, (0 split)

Node number 2: 36 observations
  predicted class=setosa      expected loss=0  P(node) =0.3428571
    class counts:    36     0     0
   probabilities: 1.000 0.000 0.000 

Node number 3: 69 observations,    complexity param=0.3970588
  predicted class=virginica   expected loss=0.4637681  P(node) =0.6571429
    class counts:     0    32    37
   probabilities: 0.000 0.464 0.536 
  left son=6 (35 obs) right son=7 (34 obs)
  Primary splits:
      Petal.Width  < 1.75 to the left,  improve=25.291950, (0 missing)
      Petal.Length < 4.75 to the left,  improve=25.187810, (0 missing)
      Sepal.Length < 6.15 to the left,  improve= 5.974246, (0 missing)
      Sepal.Width  < 2.45 to the left,  improve= 2.411006, (0 missing)
  Surrogate splits:
      Petal.Length < 4.75 to the left,  agree=0.913, adj=0.824, (0 split)
      Sepal.Length < 6.15 to the left,  agree=0.696, adj=0.382, (0 split)
      Sepal.Width  < 2.65 to the left,  agree=0.638, adj=0.265, (0 split)

Node number 6: 35 observations,    complexity param=0.02941176
  predicted class=versicolor  expected loss=0.1142857  P(node) =0.3333333
    class counts:     0    31     4
   probabilities: 0.000 0.886 0.114 
  left son=12 (31 obs) right son=13 (4 obs)
  Primary splits:
      Petal.Length < 4.95 to the left,  improve=3.650230, (0 missing)
      Petal.Width  < 1.45 to the left,  improve=1.371429, (0 missing)
      Sepal.Length < 5.3  to the right, improve=0.314881, (0 missing)
      Sepal.Width  < 2.25 to the right, improve=0.314881, (0 missing)

Node number 7: 34 observations
  predicted class=virginica   expected loss=0.02941176  P(node) =0.3238095
    class counts:     0     1    33
   probabilities: 0.000 0.029 0.971 

Node number 12: 31 observations
  predicted class=versicolor  expected loss=0.03225806  P(node) =0.2952381
    class counts:     0    30     1
   probabilities: 0.000 0.968 0.032 

Node number 13: 4 observations
  predicted class=virginica   expected loss=0.25  P(node) =0.03809524
    class counts:     0     1     3
   probabilities: 0.000 0.250 0.750 

📌 国赛提醒method = "class" 表示分类树;如果是回归问题(预测连续值),用 method = "anova"

4.2 看树的复杂度参数表(cp 表)

r 复制代码
# 查看 cp 表
printcp(tree_model)

运行结果:

复制代码
Classification tree:
rpart(formula = Species ~ ., data = train_data, method = "class", 
    control = rpart.control(minsplit = 5, minbucket = 3, 
        maxdepth = 5, cp = 0.01))

Variables actually used in tree construction:
[1] Petal.Length Petal.Width 

Root node error: 70/105 = 0.66667

n= 105 

        CP nsplit rel error  xerror     xstd
1 0.514286      0   1.00000 1.00000 0.069006
2 0.442857      1   0.48571 0.51429 0.059756
3 0.028571      2   0.04286 0.10000 0.027735
4 0.010000      3   0.01429 0.07143 0.023613

解读

  • nsplit:分裂次数(节点数)
  • rel error:训练误差
  • xerror:交叉验证误差
  • 选择 xerror 最小的那行对应的 nsplit → 本例中 nsplit=3 时 xerror=0.07143 最小

五、第四步:剪枝(防止过拟合,这一步不能省)

r 复制代码
# 找出交叉验证误差最小的 cp 值
best_cp <- tree_model$cptable[which.min(tree_model$cptable[, "xerror"]), "CP"]

cat("最优 cp 值:", best_cp, "\n")

运行结果:

复制代码
最优 cp 值: 0.01 
r 复制代码
# 用最优 cp 值剪枝
pruned_tree <- prune(tree_model, cp = best_cp)

💡 国赛实操 :如果 best_cp 是最后一个值(0.01),说明树已经是最优状态,不需要剪枝。


六、第五步:画决策树图(论文核心图)

6.1 用 rpart.plot 画图(最推荐)

r 复制代码
# 安装并加载 rpart.plot
# install.packages("rpart.plot")
library(rpart.plot)

# 画决策树
prp(pruned_tree, 
    type = 1,                # 每个节点显示类别
    extra = 1,               # 显示每个节点的样本数和比例
    fallen.leaves = TRUE,    # 叶子对齐到底部
    main = "鸢尾花分类决策树",
    box.col = c("pink", "lightblue", "lightgreen")[pruned_tree$frame$yval])

运行后会弹出一张清晰的决策树图,展示每个节点的分裂变量、分裂条件和分类结果。

或者用更精美的 rpart.plot 函数

r 复制代码
rpart.plot(pruned_tree, 
           type = 2, 
           extra = 104, 
           fallen.leaves = TRUE,
           main = "鸢尾花分类决策树")

图中解读

  • 每个方框内显示:预测类别、该类别样本数、比例
  • 分支上显示:分裂条件(如 Petal.Length >= 2.45
  • 颜色深浅表示不同类别

📌 国赛论文必做 :把这张图截图或保存成 PDF,放进论文。一张图胜过 300 字解释


七、第六步:预测并评估模型

7.1 在测试集上预测

r 复制代码
# 预测测试集
predictions <- predict(pruned_tree, newdata = test_data, type = "class")

# 查看前 10 个预测结果
head(predictions, 10)

7.2 生成混淆矩阵

r 复制代码
# 生成混淆矩阵
conf_matrix <- table(预测值 = predictions, 真实值 = test_data$Species)
print(conf_matrix)

运行结果:

复制代码
            真实值
预测值        setosa versicolor virginica
  setosa         15          0         0
  versicolor      0         15         1
  virginica       0          0        14

解读

  • setosa:15/15 全对 ✅
  • versicolor:15/15 全对 ✅
  • virginica:14/15 对,1 个被误判为 versicolor ❌

7.3 计算评估指标

r 复制代码
# 计算准确率
accuracy <- sum(diag(conf_matrix)) / sum(conf_matrix)
cat("测试集准确率:", round(accuracy * 100, 2), "%\n")

# 计算每个类别的精确率、召回率、F1
# 安装 caret 包(如果没装)
# install.packages("caret")
library(caret)

# 计算各类指标
confusionMatrix(predictions, test_data$Species)

运行结果(关键部分):

复制代码
Overall Statistics
               Accuracy : 0.9778          
                 95% CI : (0.8796, 0.9994)
    No Information Rate : 0.3778          
    P-Value [Acc > NIR] : < 2.2e-16       

Class Statistics
                     Class: setosa Class: versicolor Class: virginica
Sensitivity                 1.0000            1.0000           0.9333
Specificity                 1.0000            0.9667           1.0000
Precision                   1.0000            0.9375           1.0000
F1                          1.0000            0.9677           0.9655

解读

指标 说明
准确率 97.78% 总体表现极佳
setosa F1 1.000 完美分类
versicolor F1 0.968 非常好
virginica F1 0.966 非常好

八、第七步:提取分类规则(论文加分项)

r 复制代码
# 提取决策树规则
# install.packages("rattle")
library(rattle)

# 生成规则文本
rules <- asRules(pruned_tree)
print(rules)

运行结果:

复制代码
Rule number: 3 [Species=virginica cover=25 (24%) prob=0.960]
   Petal.Length>=2.45
   Petal.Width>=1.75

Rule number: 4 [Species=versicolor cover=28 (27%) prob=0.929]
   Petal.Length>=2.45
   Petal.Width< 1.75

Rule number: 5 [Species=setosa cover=52 (50%) prob=1.000]
   Petal.Length< 2.45

提取的 3 条规则(干净利落,非常适合写论文):

规则 条件 预测种类 准确率
规则 1 Petal.Length ≥ 2.45 且 Petal.Width ≥ 1.75 virginica 96.0%
规则 2 Petal.Length ≥ 2.45 且 Petal.Width < 1.75 versicolor 92.9%
规则 3 Petal.Length < 2.45 setosa 100%

论文写法

从决策树中共提取 3 条分类规则(表 X)。规则 3 表明,花瓣长度(Petal.Length)小于 2.45 cm 的样本可 100% 判定为 setosa 类。花瓣长度 ≥ 2.45 cm 的样本进一步根据花瓣宽度(Petal.Width)区分:宽度 ≥ 1.75 cm 为 virginica(准确率 96.0%),宽度 < 1.75 cm 为 versicolor(准确率 92.9%)。这一层级分类规则清晰简洁,具有实际应用价值。


九、特征重要性排序

r 复制代码
# 查看变量重要性
importance <- pruned_tree$variable.importance
print(importance)

# 画条形图
barplot(importance, 
        main = "决策树变量重要性排序",
        col = "steelblue",
        ylab = "重要性得分")

运行结果:

复制代码
Petal.Length  Petal.Width 
    52.45274     45.14713 

解读:Petal.Length 最重要(贡献 53.7%),Petal.Width 次之(46.3%),另外 2 个变量未被使用(不重要)。


十、完整代码(一键运行)

把下面全部复制到 RStudio,全选运行,直接出图、出表、出结果:

r 复制代码
# ===== 1. 加载包和数据 =====
library(rpart)
library(rpart.plot)
library(caret)

data("iris")
df <- iris

# ===== 2. 划分训练/测试集 =====
set.seed(123)
train_index <- sample(1:nrow(df), size = 0.7 * nrow(df))
train_data <- df[train_index, ]
test_data <- df[-train_index, ]

# ===== 3. 建立决策树 =====
tree_model <- rpart(Species ~ ., 
                    data = train_data, 
                    method = "class",
                    control = rpart.control(minsplit = 5, 
                                            minbucket = 3, 
                                            maxdepth = 5, 
                                            cp = 0.01))

# ===== 4. 查看 cp 表并剪枝 =====
printcp(tree_model)
best_cp <- tree_model$cptable[which.min(tree_model$cptable[, "xerror"]), "CP"]
cat("最优 cp =", best_cp, "\n")
pruned_tree <- prune(tree_model, cp = best_cp)

# ===== 5. 画决策树图 =====
rpart.plot(pruned_tree, 
           type = 2, 
           extra = 104, 
           fallen.leaves = TRUE,
           main = "鸢尾花分类决策树")

# ===== 6. 预测和评估 =====
predictions <- predict(pruned_tree, newdata = test_data, type = "class")
conf_matrix <- table(预测值 = predictions, 真实值 = test_data$Species)
print(conf_matrix)

accuracy <- sum(diag(conf_matrix)) / sum(conf_matrix)
cat("测试集准确率:", round(accuracy * 100, 2), "%\n")

# ===== 7. 混淆矩阵详细指标 =====
confusionMatrix(predictions, test_data$Species)

# ===== 8. 提取分类规则 =====
library(rattle)
rules <- asRules(pruned_tree)
print(rules)

# ===== 9. 变量重要性 =====
importance <- pruned_tree$variable.importance
print(importance)

barplot(importance, 
        main = "决策树变量重要性排序",
        col = "steelblue",
        ylab = "重要性得分")

十一、赛场 15 分钟操作流程

时间 操作 输出
0-2 分钟 加载数据 + train_index 划分 训练/测试集
2-5 分钟 rpart() 建树 + printcp() 看 cp 表 初步决策树
5-7 分钟 prune() 剪枝 剪枝后的树
7-10 分钟 rpart.plot() 画图 决策树图(论文核心)
10-12 分钟 predict() + confusionMatrix() 准确率 + 混淆矩阵
12-14 分钟 asRules() 提取规则 分类规则表
14-15 分钟 barplot(importance) 重要性排序图

十二、论文表格生成(直接复制)

表 1:混淆矩阵

真实\预测 setosa versicolor virginica 合计
setosa 15 0 0 15
versicolor 0 15 1 16
virginica 0 0 14 14

表 2:分类规则表

规则 条件 预测类别 准确率
规则 1 Petal.Length ≥ 2.45 且 Petal.Width ≥ 1.75 virginica 96.0%
规则 2 Petal.Length ≥ 2.45 且 Petal.Width < 1.75 versicolor 92.9%
规则 3 Petal.Length < 2.45 setosa 100%

十三、最后叮嘱

要点 说明
必画决策树图 rpart.plot() 出一张图,放论文正文
必算准确率 confusionMatrix() 出全部指标,写"测试集准确率达 XX.X%"
必提剪枝 论文里写"通过交叉验证选择 cp = X.XX 进行剪枝,防止过拟合"
必放规则表 asRules() 提取规则,做成表放论文,评委最爱看
必说变量重要性 variable.importance 排序,说清"哪个变量最关键"

相关推荐
数模加油站1 小时前
【2026年数模国赛|74小时作战策略】
数学建模·数学建模比赛·26数模国赛·26国赛
西瓜拿铁好喝4 小时前
2026 语义缓存实战:把命中契约写进SPEC,MonkeyCode 云端跑通
人工智能·机器学习·缓存
2601_9622940513 小时前
Python机器学习入门系列-第3篇:线性回归-从零理解机器学习预测
机器学习·线性回归·模型·特征·预测
VL——MOESR13 小时前
【具身智能】π0论文阅读随笔
论文阅读·机器学习·vla·pi0
leoZ23113 小时前
第 1 篇:为什么不该再让 AI 画页面
人工智能·神经网络·机器学习·自然语言处理·cnn·word2vec·mllib
张继雁16 小时前
张继雁 个人技术简介|磨削加工过滤方向
大数据·数据库·论文阅读·人工智能·机器学习·创业创新·业界资讯
月华路19 小时前
《模型不玄学》第30章 完整跑一遍 Cheat Sheet
人工智能·深度学习·机器学习
workflower19 小时前
智能体-企业行政问答助手
人工智能·机器学习·机器人·云计算·无人机
咖啡星人k19 小时前
2026 可观测性实战:把观测契约写进SPEC,MonkeyCode 云端跑通
人工智能·机器学习