数据挖掘与R语言

第4讲:矩阵、列表、数组与数据框——更多数据对象

2026年09月09日

本讲导览

Matrix · List · Array · Data Frame

  • 一、复习导入 ——向量、因子、数据框够用吗?为什么还需要更多数据对象?
  • 二、矩阵(Matrix) ——创建、命名与索引
  • 三、矩阵运算 ——财务报表怎么用矩阵表示
  • 四、列表(List) ——什么都能装的百宝箱
  • 五、数组(Array) ——矩阵的多维升级版
  • 六、数据框进阶 ——从Base R到dplyr的桥梁
  • 七、课堂总结与Exit Ticket ——把六大数据对象串成一张体系图

提示

今天把R语言的数据对象工具箱补充完整,前半节认识矩阵、列表、数组,后半节回到最常用的数据框,学几招更好用的处理方式——学完今天,你会拥有六件趁手的工具:向量、矩阵、数组、因子、列表、数据框。

一、复习导入

为什么还需要更多数据对象?

1.1 复习提问

  • 向量、因子、数据框分别是什么?请每人举一个财务场景的例子

复习口诀:“文本最强,遇串皆串”——这个隐式转换的逻辑,今天在矩阵里还会用到。

1.2 情境导入 —— 两个引导问题

问题一:如果要表示“3家公司 × 4个季度”的营收数据(一张12格的表),向量装得下吗?

能装,但没有“行列”结构,不好按行按列取数——这就是矩阵要解决的问题

问题二:如果想把“公司名称、成立年份、是否上市、近三年营收”这些类型各不相同的信息打包在一起,数据框只能存“等长的列”,能满足吗?

不能——这就是列表要解决的问题

1.3 今天要补齐的工具箱

数据框是最常用的“表格”,但矩阵(纯数值的表格)、列表(万能百宝箱)、数组(多维表格)是数据框做不到的场景下的补充工具——今天把工具箱补充完整之后,后半节课再回到数据框,学几招更好用的处理方式

二、矩阵(Matrix)——创建、命名与索引

二维的同类型数据

2.1 矩阵的创建

▶️ 查看代码
revenue_matrix <- matrix(
  c(120,135,128,150, 80,95,88,100, 200,210,205,220),
  nrow = 3, byrow = TRUE)
revenue_matrix
     [,1] [,2] [,3] [,4]
[1,]  120  135  128  150
[2,]   80   95   88  100
[3,]  200  210  205  220

警告

nrow=3告诉R这是3行;byrow=TRUE表示按行填充数据——注意:R默认按列填充byrow=FALSE),这是新手最容易踩的坑,现场对比两种填充方式的差异。

注记

矩阵和向量一样,所有元素必须是同一种数据类型(复习“文本最强,遇串皆串”——矩阵中混入一个字符串,整个矩阵都会变成字符串型)。

2.2 矩阵的行列命名与索引

▶️ 查看代码
rownames(revenue_matrix) <- c("贵州茅台", "五粮液", "泸州老窖")
colnames(revenue_matrix) <- c("Q1", "Q2", "Q3", "Q4")
revenue_matrix
          Q1  Q2  Q3  Q4
贵州茅台 120 135 128 150
五粮液    80  95  88 100
泸州老窖 200 210 205 220
▶️ 查看代码
revenue_matrix[1, ]                # 第一行(贵州茅台全年数据)
 Q1  Q2  Q3  Q4 
120 135 128 150 
▶️ 查看代码
revenue_matrix["五粮液", "Q3"]      # 用行列名索引
[1] 88

课堂练习:取出泸州老窖全年的营收数据(提示:用行名索引)

2.3 课堂练习参考答案

▶️ 查看代码
revenue_matrix["泸州老窖", ]   # 用行名索引,取出整行
 Q1  Q2  Q3  Q4 
200 210 205 220 

提示

revenue_matrix["五粮液", "Q3"]是同一套逻辑——只指定行名、不指定列名,即取出该行的全部列。

三、矩阵运算——财务报表场景

财务报表怎么用矩阵表示

3.1 矩阵的向量化运算与汇总函数

▶️ 查看代码
revenue_matrix * 1.1     # 全部营收上浮10%(向量化运算同样适用于矩阵!)
          Q1  Q2    Q3  Q4
贵州茅台 132 148 140.8 165
五粮液    88 105  96.8 110
泸州老窖 220 231 225.5 242
▶️ 查看代码
rowSums(revenue_matrix)  # 每家公司全年营收合计
贵州茅台   五粮液 泸州老窖 
     533      363      835 
▶️ 查看代码
colSums(revenue_matrix)  # 每个季度三家公司合计
 Q1  Q2  Q3  Q4 
400 440 421 470 

注记

了解一下:t()可以转置矩阵(行列互换),cbind()/rbind()可以增加列/行,用到时再查文档即可,今天不做展开练习。

3.2 财务场景练习

rowSums()计算三家公司的年度总营收,再结合which.max()rownames()找出年度营收最高的公司

3.3 财务场景练习参考答案

▶️ 查看代码
annual_totals <- rowSums(revenue_matrix)   # 每家公司的年度总营收
annual_totals
贵州茅台   五粮液 泸州老窖 
     533      363      835 
▶️ 查看代码
rownames(revenue_matrix)[which.max(annual_totals)]   # 年度营收最高的公司
[1] "泸州老窖"

提示

which.max()返回的是位置(第几个),不是公司名,所以要配合rownames()把位置翻译回名字——这个组合以后会经常用到。

四、列表(List)——万能容器

什么都能装的百宝箱

4.1 列表是什么

类比:向量、矩阵要求元素类型一致,数据框要求每列等长;列表没有这些限制——可以同时装数值、字符串、向量、数据框,甚至列表本身

4.2 列表的创建与索引

▶️ 查看代码
company_info <- list(
  name = "贵州茅台",
  founded = 1951,
  is_listed = TRUE,
  quarterly_revenue = c(120, 135, 128, 150)
)
company_info$name                       # 用$按名字取
[1] "贵州茅台"
▶️ 查看代码
company_info[["quarterly_revenue"]]     # 用[[ ]]按名字取
[1] 120 135 128 150
▶️ 查看代码
company_info[[4]]                       # 用[[ ]]按位置取
[1] 120 135 128 150
▶️ 查看代码
company_info[4]                         # 对比:用[ ]按位置取——结果仍是一个列表!
$quarterly_revenue
[1] 120 135 128 150

重要

[ ]取出的是“仍然装在列表里的一份”(打开看还是个盒子),[[ ]]取出的是“盒子里真正的内容”——这是列表最容易搞混的地方,现场对比class(company_info[4])class(company_info[[4]])的输出差异。这个知识点待会儿在数据框进阶环节还会用到,请务必掌握。

4.3 财务场景练习

创建一个列表,包含某公司的名称、成立年份、近三年营收(向量)、信用评级(因子),并用$取出营收向量计算平均值

4.4 财务场景练习参考答案

▶️ 查看代码
company2 <- list(
  name = "五粮液",
  founded = 1952,
  revenue_3y = c(560, 620, 680),
  credit_rating = factor("AAA", levels = c("AA", "AAA", "AAA+"))
)
mean(company2$revenue_3y)   # 用$取出营收向量,再求平均值
[1] 620

提示

四个元素、四种类型(字符、数值、数值向量、因子)装在同一个列表里——这正是列表“什么都能装”的体现,换成数据框是做不到的。

五、数组(Array)——多维数据

矩阵的多维升级版

5.1 数组是什么

类比:矩阵是二维(行×列)的表格,数组可以是三维甚至更多维(如“公司×季度×年份”的三维营收数据)

▶️ 查看代码
revenue_array <- array(1:24, dim = c(3, 4, 2))   # 3家公司×4个季度×2年
revenue_array[1, 2, 1]                            # 第1家公司、第2季度、第1年的数据
[1] 4

注记

数组在实际财务分析中不算高频工具(多数场景用数据框或列表就足够了),此处只需要“眼熟”,知道R语言有这个工具、遇到多维数据时可以考虑它即可,不安排课堂练习。

六、数据框进阶——从Base R到dplyr的桥梁

向量、矩阵、数组这一条“同类型、维度递增”的家族已经认识完整,回到最常用的数据框,学几招更好用的处理方式

6.1 数据框结构探查

▶️ 查看代码
df <- data.frame(
  company = c("贵州茅台", "五粮液", "泸州老窖"),
  revenue_2025 = c(1500, 680, 320),
  profit_2025 = c(750, 200, 90),
  listed = c(TRUE, TRUE, TRUE)
)
str(df)
'data.frame':   3 obs. of  4 variables:
 $ company     : chr  "贵州茅台" "五粮液" "泸州老窖"
 $ revenue_2025: num  1500 680 320
 $ profit_2025 : num  750 200 90
 $ listed      : logi  TRUE TRUE TRUE
▶️ 查看代码
summary(df)
      company   revenue_2025   profit_2025   listed       
 Length   :3   Min.   : 320   Min.   : 90   Mode:logical  
 N.unique :3   1st Qu.: 500   1st Qu.:145   TRUE:3        
 N.blank  :0   Median : 680   Median :200                 
 Min.nchar:3   Mean   : 833   Mean   :347                 
 Max.nchar:4   3rd Qu.:1090   3rd Qu.:475                 
               Max.   :1500   Max.   :750                 
▶️ 查看代码
dim(df); nrow(df); ncol(df)
[1] 3 4
[1] 3
[1] 4
▶️ 查看代码
names(df)
[1] "company"      "revenue_2025" "profit_2025"  "listed"      

提示

str()是认识一个陌生数据框最快的方式,以后拿到任何数据集,第一件事就是str()一下。

6.2 用逻辑向量做条件筛选

▶️ 查看代码
df[df$revenue_2025 > 500, ]                              # 筛选营收超过500的公司(保留所有列)
   company revenue_2025 profit_2025 listed
1 贵州茅台         1500         750   TRUE
2   五粮液          680         200   TRUE
▶️ 查看代码
df[df$profit_2025 > 100, c("company", "profit_2025")]    # 筛选+只看指定列
   company profit_2025
1 贵州茅台         750
2   五粮液         200

这个写法是不是很眼熟?第2课学过revenue[revenue > 130]对向量做筛选,这里是对数据框的做同样的事。

注记

预告:下节课/项目二会学dplyr::filter(df, revenue_2025 > 500),效果完全一样,只是写法更顺手——今天先打好base R的底子。

6.3 数据框的本质:一种特殊的列表

▶️ 查看代码
class(df)
[1] "data.frame"
▶️ 查看代码
is.list(df)
[1] TRUE
▶️ 查看代码
df[["company"]]   # 列表的取法
[1] "贵州茅台" "五粮液"   "泸州老窖"
▶️ 查看代码
df$company        # 数据框的取法——和列表的$是同一套逻辑
[1] "贵州茅台" "五粮液"   "泸州老窖"

重要

呼应四、列表小节:数据框每一列可以是不同类型(revenue_2025数值型、listed逻辑型),但所有列必须等长——这正是“特殊的列表”。

6.4 财务场景综合练习

df中筛选出“上市且营收超过500”的公司(提示:用&连接两个逻辑条件,写法与向量的多条件筛选一致),并计算这些公司的平均利润率(profit_2025/revenue_2025

6.5 财务场景综合练习参考答案

▶️ 查看代码
selected <- df[df$listed & df$revenue_2025 > 500, ]   # & 连接两个逻辑条件
selected
   company revenue_2025 profit_2025 listed
1 贵州茅台         1500         750   TRUE
2   五粮液          680         200   TRUE
▶️ 查看代码
mean(selected$profit_2025 / selected$revenue_2025)     # 平均利润率
[1] 0.397

提示

df$listed & df$revenue_2025 > 500先各自生成一个逻辑向量,再用&按位置“与”起来——和第2课向量的多条件筛选(如revenue > 100 & revenue < 200)是完全一样的写法。

七、课堂总结、六大数据对象体系梳理与Exit Ticket

把六大数据对象串成一张体系图

7.1 六大数据对象体系梳理

flowchart TD
    V["向量 Vector<br/>一维,同类型"]
    V --> M["矩阵 Matrix<br/>二维,同类型"]
    M --> AR["数组 Array<br/>多维,同类型"]
    V --> F["因子 Factor<br/>带类别标签的向量"]
    V --> L["列表 List<br/>一维,任意类型"]
    L --> DF["数据框 Data Frame<br/>列等长的特殊列表"]

    style V fill:#1a3a5c,color:#fff
    style M fill:#2e5984,color:#fff
    style AR fill:#2e5984,color:#fff
    style F fill:#375623,color:#fff
    style L fill:#7a4419,color:#fff
    style DF fill:#7a4419,color:#fff

  • 第一条线——“同类型、维度递增”:向量(1维) → 矩阵(2维) → 数组(多维),三者都要求元素类型一致
  • 第二条线——“功能特化”:向量 → 因子(带类别标签、有水平levels的特殊向量)
  • 第三条线——“放松类型限制”:向量 → 列表(1维、任意类型) → 数据框(特殊的列表,要求每一列等长)

提问串联:数据框的本质是什么?——六(3)刚验证过:是一种特殊的列表,每一列可以是不同类型,但所有列必须等长,取值方式$[[ ]]与列表完全一致。

7.2 学习成果自查

对照一下,今天这几件事你都做到了吗?

  • ✓ 能够创建矩阵并进行行列索引
  • ✓ 能够运用rowSums()/colSums()等函数对矩阵进行汇总
  • ✓ 能够创建列表并区分[ ][[ ]]的取值差异
  • ✓ 能够说出数组与矩阵的维度关系
  • ✓ 能够用str()、条件筛选对数据框做进阶操作,并说出“数据框是特殊列表”的原理
  • ✓ 能够梳理六大数据对象之间的联系与区别

提示

如果有没打勾的,下课后一定要找同学或老师补上,不要留到下一讲。

7.3 Exit Ticket —— 写给自己的三个问题

请花1分钟,在纸条或在线问卷上简要回答:

  1. 矩阵和数据框最大的区别是什么?
  2. 列表的[ ][[ ]]取数有什么不同?
  3. 为什么说数据框是“一种特殊的列表”?

7.4 Exit Ticket 参考答案

  • 问题一:矩阵要求所有元素同一种数据类型(二维、纯数值/纯字符),数据框允许每一列类型不同,但矩阵和数据框都要求行列(或各列)对齐、等长——这是矩阵和数据框最大的区别。
  • 问题二[ ]取出的结果仍然是一个列表(打开还是个盒子),[[ ]]取出的是盒子里真正的内容(脱离了列表这层包装)——可以用class()验证两者输出类型不同。
  • 问题三:因为is.list(df)返回TRUE——数据框本质上就是一种列表,取值方式($[[ ]])与列表完全一致,只是数据框额外要求“每一列必须等长”,这是数据框相比普通列表多出来的限制。

提示

对照一下自己纸条上写的答案,理解偏差的地方现在举手提问,别留到下节课。

课后作业

矩阵、列表与数据框综合练习

使用Quarto(.qmd)完成以下操作,保留代码与运行结果:

  1. 矩阵:创建一个4行3列的矩阵,表示某公司近4个季度在“营收、成本、利润”三个科目上的数据(数据自定),并完成:
    • 为矩阵设置合适的行名(Q1-Q4)与列名(营收/成本/利润)
    • rowSums()或直接计算,求出每个季度的利润率(利润/营收)
    • 用索引取出“利润”这一列的数据
  2. 列表:创建一个列表,至少包含4个不同类型的元素(如公司名称、成立年份、是否上市、一个营收向量),并完成:
    • 分别用$[[ ]]两种方式取出其中一个元素
    • 对比[ ][[ ]]取同一个元素时class()的差异,并用一句话写出你的理解
  3. 数据框:在课堂df的基础上(或自建一个至少4列的数据框),完成:
    • str()查看结构
    • 用逻辑向量筛选出符合某个条件的行(如营收超过某个数值)
    • class()is.list()验证“数据框是一种特殊的列表”
  4. 【选做】创建一个简单的三维数组(如2家公司×3个季度×2年),并取出其中任意一个数据点

提交要求

提交今天课堂上练习的.qmd源文件,命名为“学号_姓名_第4课作业”,确保代码可运行、结果完整。本次作业计入平时成绩中的“实验报告”部分考核。

下讲预告

第5讲:流程控制语句——条件分支、循环、自定义函数

  • 条件分支(if/else)、循环(for/while)、自定义函数(function
  • 继续用Quarto代码块整理本节课作业,保持代码与结果一一对应的习惯

提示

课前准备:整理好今天创建的revenue_matrixcompany_infodf等对象的代码,下节课会用到类似的数据结构。

谢谢!

第4讲:矩阵、列表、数组与数据框——更多数据对象

"In God we trust; all others must bring data." — W. Edwards Deming,质量管理与统计学家

朱 奇 | 锦城大学 · 财会学院