第2讲:R语言数据类型与数据结构
2026年09月03日
Data Types & Objects
c(),再到R语言的基本积木提示
今天的目标:认识单个值的数据类型,以及多个值时数据的组织结构。
从"给一组数字批量涨价"问题,引出向量
展示上节课练习:1到20的连续整数 1:20
"如果这20个数字分别代表20天的销售额(万元),公司决定给每天销售额都上浮10%作为下季度预测,你会怎么写代码?"
不用一个个改,R可以整体处理——这就是今天的两个关键词:向量、向量化运算。
Ctrl+Shift+N,Mac:Cmd+Shift+N)Ctrl+O),或者直接在右下角Files面板里点.R文件Ctrl+S(Mac:Cmd+S),第一次保存会让你选文件名和位置提示
文件名建议见名知意,比如"学号_姓名_第2课.R";建议给每门课/每个项目单独建一个文件夹,不要都堆在桌面上,方便以后查找。
注记
留意标签页上文件名前面的小圆点:有改动但还没保存时会显示一个圆点,保存后圆点消失——这是提醒你"这份文件还有没存的改动"的信号,写完记得随手Ctrl+S,避免电脑意外重启白忙一场。
注释:#开头到这一行结束,R完全不会执行,是专门写给"人"看的
提示
好的注释解释"为什么这么做",而不是简单翻译代码——比如x <- 5 # 把5赋值给x这种注释没有意义,revenue <- c(120, 135, 128, 150) # 某公司四个季度营收才是有用的注释。
分段:脚本变长之后,用RStudio的"分节"语法给代码分块,方便折叠和跳转——注释后面跟4个以上的短横线,就会自动变成一个可折叠的分节标题:
提示
快捷键Ctrl+Shift+R(Mac:Cmd+Shift+R)可以直接插入一个分节标题;脚本变长后,按Ctrl+Shift+O(Mac:Cmd+Shift+O)打开大纲面板,点一下就能跳到对应分段,不用来回滚动鼠标找代码。
基本间距习惯:
<-、+、>等)前后加空格什么时候该换行:一行代码太长(一般建议不超过80个字符)、或者一个函数参数比较多时,可以在逗号后换行,让每个参数单独占一行:
这样比堆在一行里更容易检查——少个逗号、漏个括号,一眼就能看出来是哪一行的问题。
提示
拿不准怎么排版的时候,选中这段代码,按Ctrl+Shift+A(Mac:Cmd+Shift+A),RStudio会自动帮你重新排版(补空格、调整缩进),相当于"一键代码美化"。
| 想做什么 | 怎么操作 |
|---|---|
| 运行当前一行 | 光标停在这一行任意位置,按Ctrl+Enter(Mac:Cmd+Return),运行完自动跳到下一行 |
| 运行选中的部分代码 | 鼠标选中若干行(哪怕只是一行中的一部分),Ctrl+Enter只运行选中的内容 |
| 运行一整段(跨多行的语句) | 光标停在这段代码任意一行即可,比如上一页跨5行的data.frame(...),R会自动识别这是"一句完整的代码",整体执行,不会只运行半句 |
| 运行整个脚本 |
Ctrl+Shift+Enter(Mac:Cmd+Shift+Return),或点编辑器右上角的Source按钮,从头到尾整份文件都跑一遍 |
提示
记口诀:一行/选中都用Ctrl+Enter,全部用Ctrl+Shift+Enter。日常写代码时最常用的是"运行当前一行"——写一行、看一眼结果、再写下一行,运行整份脚本一般用在"确认整个文件从头到尾都能顺利跑通"的时候(比如交作业前)。
在R中,我们不只是"存数据",而是把数据组织成不同的数据对象——不同的对象,决定了我们以后能对这份数据做什么操作。
提示
今天这一整讲,其实都在回答一个问题:R是怎样把现实世界的数据,一步步"装进"计算机里的?
答案会是一条链条:一个值 → 向量 → 因子 / 数据框。今天先记住这条链条的样子,讲完你就会明白每一环是怎么接上的。
数值、字符、逻辑、复数——每个数据都有自己的"身份"
100默认存成double;如果想强制存成真正的整数,可以用100L(结尾加大写L)revenue > target),结果就是逻辑型[1] "2026-09-03"
[1] "Date"
[1] "2026-09-03"
[1] 20699
Time difference of 245 days
[1] "2026年09月03日"
提示
知道"日期底层是数字"这件事,能帮你理解很多"奇怪"的报错——比如不小心把日期列当成普通数值做了加减,结果得到一个诡异的天数,而不是报错。
财经数据里经常出现这类信息:所属行业(银行/科技/能源)、信用评级(低/中/高)、地区(华东/华南/华北)——它们的取值表示类别,不表示数量,统计学上把这类变量叫分类变量(categorical variable)。
分类变量又分两种:
| 特点 | 例子 | |
|---|---|---|
| 无序分类(nominal) | 类别之间没有自然顺序 | 行业:银行、科技、能源 |
| 有序分类(ordinal) | 类别之间有自然顺序,但相邻类别的"距离"不一定相等 | 信用评级:低 < 中 < 高 |
提示
判断一个变量是不是"有序",就问一句:这些类别能不能排出先后/大小? 能排的是有序分类(如评级、学历),排不出来的是无序分类(如行业、地区)。
重要
这里先留一个悬念:R要怎么表示"这是一个分类变量"、还要区分"有没有顺序"呢? 光靠字符串是做不到的——字符串只能存文字,存不了"这几个文字是一组固定类别"这件事。我们得先学会向量,再回头看R专门为这件事设计的工具。
判断以下值分别属于什么类型,用class()验证:
"成都锦城学院"TRUE20263.14 > 3一组同类型的数据放在一起
[1] 100
[1] 500 497 494 491 488 485 482 479 476 473 470 467 464 461 458 455 452 449 446
[20] 443 440 437 434 431 428 425 422 419 416 413 410 407 404 401 398 395 392 389
[39] 386 383 380 377 374 371 368 365 362 359 356 353 350 347 344 341 338 335 332
[58] 329 326 323 320 317 314 311 308 305 302
class(100),输出前面是不是总有个[1]?这不是巧合100本质上是一个长度为1的向量
[1]的意思是"这一行,是从向量的第1个元素开始显示的";向量变长后换行,你会看到行首编号跳到[26]之类的位置,帮你数清楚这是第几个元素<- —— 给数据起个名字<- 读作"赋值":把右边的结果,装进左边这个名字里Option + -,Windows Alt + -,会自动打出<-(带空格),比手打两个字符快,建议现在就养成习惯= 技术上也能赋值,但本课程和R社区主流风格一样,把=留给函数参数专用(如round(x, digits = 2)),赋值统一用<-,读代码时更容易分清硬性规则(写错R直接报错):
.、_
2025revenue❌ → revenue_2025✅(本课件后面一直这么写)Revenue和revenue是两个不同的变量TRUE、FALSE、NA、if、for、function等警告
软性的坑:变量名技术上可以随便起,但起成c <- 5会把内置的c()函数"遮住",导致后面c(1,2,3)莫名报错——现场演示一下这个陷阱,起名时避开c、mean、sum这类常用函数名。
x不如revenue一眼看懂snake_case(单词间加下划线),如revenue_2025、is_profit
c是英文combine(合并、组合)的缩写,作用就是把多个单独的值粘合成一个向量c(...)
c()不仅能合并单个数值,也能合并向量本身:c(revenue, 160)就是在原向量末尾再加一个新数据[1] 120 135 128 150
警告
向量中所有元素必须是同一种数据类型,否则R会自动"降级"转换——c(1, "a") 会把 1 也变成字符串 "1"。现场试一下这个"陷阱"。
课堂练习:创建一个包含你所在小组5名同学姓名的字符向量
R的索引本质上只回答一个问题:我想要哪些位置?
[1] 120
[1] 135 128
[1] 135 128 150
[1] 120 128
正向、负向、逻辑索引看起来是三种语法,其实都在做同一件事——x[ ]就是从x中选出我想要的元素,这个统一认知对后面筛选数据框非常重要。
逻辑索引拆开看一步:
[1] FALSE TRUE FALSE TRUE
[1] 135 150
重要
跟 Python 不一样! Python里revenue[-1]是"取最后一个",但R里的负索引是"排除"——revenue[-1]意思是"除了第一个之外的所有元素",不是"最后一个"。要真正取到最后一个值,得用下面这两种写法:
[1] 150
[1] 150
课堂练习:写出获取revenue中最后一个季度数据的两种不同写法
[1] 132 148 141 165
[1] -13.25 1.75 -5.25 16.75
[1] 533
[1] 133
[1] 30
对比一下:如果不用向量化,得这样写
哪一种更符合今天"批量处理一组数据"的任务?答案很直观。
重要
在R中,如果一个操作可以自然地向量化完成,优先考虑向量化,而不是手动写循环——这是R处理数据的核心优势,不代表循环是坏东西,只是很多场景下向量化更简洁、更不容易出错。回到开头的问题:现在能一行代码算出20天销售额上浮10%后的结果了吗?(1:20) * 1.1
课堂练习:某产品连续6个月销售额为c(45,52,48,60,55,58),计算总销售额、平均销售额,并找出销售额超过50的月份
[1] 4
[1] 120 128 135 150
[1] 150 135 128 120
[1] 4
[1] 1
which.max()找到位置,quarter[...]结合这个位置反查"是哪个季度",这个"先定位、再反查"的思路,为项目二"数据准备"中按条件筛选数据打下基础sort()再取值)回收一个悬念:R怎么表示"分类"这件事?
还记得第二部分留下的悬念吗?——分类变量要怎么在R里表示?现在你已经学会向量了,答案揭晓:
字符向量能存下这几个字母,但它不知道"A、B、C是一组固定的类别"——它只当这是普通文本。R专门设计了因子(factor)来解决这个问题:它不仅记录每条数据属于哪个类别,还记录这个变量总共有哪些可能的类别(levels)。
注记
因子到底算类型还是算结构? 老实说,两边都不完全是——它在R底层是"整数向量 + 一张标签表",所以天生卡在中间:从使用体验上看,它更像字符型的一个"专业版"(表示分类文本);从底层实现看,它建立在向量之上。这一讲刚学的日期型其实也是同样的处理方式(数值向量+特殊标记)。记住它是"分类变量在R里的具体实现"就够了,不用纠结该归到哪一类。
[1] "factor"
[1] "A" "B" "C"
rating_f
A B C
2 2 1
注记
因子的"水平"(levels)就是它可能取值的全部类别,这是因子与普通字符串最大的区别。这里的rating是无序分类——A、B、C之间不存在谁比谁"更高"的关系,只是三个不同标签。
[1] 低 中 高 中 低
Levels: 低 < 中 < 高
[1] TRUE
这里的risk是有序分类——多了ordered = TRUE和按顺序排好的levels,R就知道"低<中<高"这个大小关系,能直接比较。财务场景:风险等级、信用评级都天然带有高低顺序,用有序因子表示比普通字符串更符合业务逻辑,为后续回归分析中"虚拟变量"的处理打下基础。
课堂练习:将某公司四个季度的"业绩评价"(合格、优秀、良好、优秀)转换为因子并用table()统计各等级出现次数
像Excel一样的表格
类比:Excel中一行是一条记录,一列是一个字段;数据框也是如此,只不过每一"列"背后其实就是我们刚学的向量
'data.frame': 3 obs. of 3 variables:
$ company : chr "贵州茅台" "五粮液" "泸州老窖"
$ revenue_2025: num 1500 680 320
$ rating_f : Factor w/ 3 levels "A","B","C": 1 1 2
[1] 3 3
[1] "company" "revenue_2025" "rating_f"
[1] 1500 680 320
注记
数据框的索引统一写成 df[行, 列]——逗号左边选行,右边选列,不写就代表"全部"。所以:
company revenue_2025 rating_f
1 贵州茅台 1500 A
2 五粮液 680 A
[1] "贵州茅台" "五粮液"
注记
数据框的每一"列"本质就是一个向量——这也是为什么前面要先扎实掌握向量操作。数据框只是把多个向量按行对齐组合在一起。完整的数据导入(CSV/Excel)、数据清洗与变换操作,将在项目二"数据准备"中系统展开,今天只做初步认识。
课堂互动:数据框和Excel表格有什么相似之处?又有什么是Excel做不到、但R数据框能做到的?
R和很多扩展包里自带了大量现成的数据框,可以直接拿来用,不用每次都自己敲c():
[1] "data.frame"
sr pop15 pop75 dpi ddpi
Australia 11.43 29.4 2.87 2330 2.87
Austria 12.07 23.3 4.41 1508 3.93
Belgium 13.17 23.8 4.43 2108 3.82
Bolivia 5.75 41.9 1.67 189 0.22
Brazil 12.88 42.2 0.83 728 4.56
'data.frame': 50 obs. of 5 variables:
$ sr : num 11.43 12.07 13.17 5.75 12.88 ...
$ pop15: num 29.4 23.3 23.8 41.9 42.2 ...
$ pop75: num 2.87 4.41 4.43 1.67 0.83 2.85 1.34 0.67 1.06 1.14 ...
$ dpi : num 2330 1508 2108 189 728 ...
$ ddpi : num 2.87 3.93 3.82 0.22 4.56 2.43 2.67 6.51 3.08 2.8 ...
LifeCycleSavings是R自带的经济学数据集,每一行是一个国家,列包括总储蓄率(sr)、少儿/老年人口占比(pop15/pop75)、人均可支配收入(dpi)及其增长率(ddpi)data()可以列出当前已加载扩展包里所有自带数据集的名字,感兴趣可以自己找几个看看 dpi sr
Australia 2330 11.43
Belgium 2108 13.17
Canada 2983 8.79
Denmark 2497 16.85
France 2214 12.64
Germany 2457 12.55
Luxembourg 2449 10.35
Norway 2231 10.25
Sweden 3299 6.86
Switzerland 2631 14.13
United States 4002 7.56
今天重点掌握的是向量和数据框,但R还有三个"近亲"结构,值得知道它们的存在和大致定位(不要求今天就会用):
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
, , 3
[,1] [,2] [,3]
[1,] 13 15 17
[2,] 14 16 18
, , 4
[,1] [,2] [,3]
[1,] 19 21 23
[2,] 20 22 24
$name
[1] "贵州茅台"
$price
[1] 1680
$code
[1] "600519"
| 结构 | 维度 | 元素类型 | 一句话定位 |
|---|---|---|---|
| 向量 Vector | 一维 | 必须同类型 | 今天的主角,最基本的积木 |
| 矩阵 Matrix | 二维 | 必须同类型 | 向量的二维版本 |
| 数组 Array | 可以更多维 | 必须同类型 | 矩阵的高维版本 |
| 列表 List | 不限 | 可以不同类型 | 最灵活的"百宝箱" |
| 数据框 Data Frame | 二维(行×列) | 列与列之间可以不同类型 | 分析数据最常用的结构 |
提示
一个值得记住的关系:数据框本质上是一种特殊的列表——每一列是列表里的一个元素(一个向量),只是要求所有列长度相等、摆成表格的样子。以后你会在str(df)的输出里看到List of ...字样,就是这个原因。
矩阵/数组主要用在纯数值计算(比如矩阵乘法),列表常用来打包"一次分析的所有结果"(比如既要存数字又要存图表)。这两个今天不展开操作,项目后续用到时再详细讲。
把今天学的数据世界串成一张图
flowchart TD
R["R中的数据"] --> V0["一个值<br/>其实是长度为1的向量"]
R --> V["多个值<br/>向量 Vector"]
V --> T["元素的数据类型<br/>数值/字符/逻辑/复数/日期"]
V --> F["因子 Factor<br/>分类变量的R实现"]
V --> M["矩阵/数组<br/>向量的二维/高维版本"]
V --> L["列表 List<br/>可装不同类型的百宝箱"]
L --> D["数据框 Data Frame<br/>一种特殊的列表"]
style R fill:#1a3a5c,color:#fff
style V0 fill:#2e5984,color:#fff
style V fill:#2e5984,color:#fff
style T fill:#375623,color:#fff
style F fill:#375623,color:#fff
style M fill:#375623,color:#fff
style L fill:#375623,color:#fff
style D fill:#843c0c,color:#fff
对照一下,今天这几件事你都做到了吗?
table()统计类别$、[行,列]提取指定内容head()/str()查看一个R自带的数据集提示
如果有没打勾的,下课后一定要找同学或老师补上,不要留到下一讲。
请花1分钟,在纸条或在线问卷上简要回答:
revenue <- c(80, 120, 90, 150),怎么选出所有超过100的值?注记
这不是考试,是帮你自己梳理今天学到了什么,也帮老师了解下节课该怎么调整节奏。
在RStudio中新建一个R脚本(.R文件),完成以下操作并保留代码与结果:
100、"财务分析"、TRUE、3.14
which.max()/which.min())table()统计各等级人数str()查看结构$取出"分数"这一列注记
财务综合小练习:某公司三个产品(A、B、C)某月销售额分别为85万元、120万元、96万元,请用向量表示这组数据,计算总销售额、平均销售额,并找出表现最好的产品
提交要求
将上述练习的代码和运行结果截屏,整理在一个Word文档中,命名为"学号_姓名_第2课作业.docx"提交。本次作业计入平时成绩中的"实验报告"部分,请按时提交并保证代码可运行、截图清晰。
这是我们最后一次要求"截图+整理Word"的作业形式。 从第3讲开始,我们会用Quarto一键把代码和结果直接生成报告——你现在手动做的这件事,很快就会变成计算机自动帮你完成。
第3讲:Markdown语法与Quarto文档写作
提示
课前准备:确保R脚本能正常保存、运行;如果RStudio还有装不上的问题,提前联系老师。
第2讲:R语言数据类型与数据结构
"In God we trust; all others must bring data." — W. Edwards Deming,质量管理与统计学家
朱 奇 | 锦城大学 · 财会学院
数据挖掘与R语言 | 第2讲:R语言数据类型与数据结构