R基础
R 中对任何函数使用 ? 或 help 可以打开对应的介绍文档, 如
对于任意 R object, 都可以使用 typeof() 和 str() 查看其类型与内部结构, 如
请同学们在接下来的内容中必要时使用这些特性自行探索.
基本数据结构
R 语言的基本数据结构可以根据其维度 (一维, 二维, 多维) 以及同质性 (所有内容必须为同一类型) 或异质性 (内容可以是不同类型) 分类.
| 维度 | 同质 | 异质 |
|---|---|---|
| 1d | Atomic vector | List |
| 2d | Matrix | Data frame |
| nd | Array |
原子向量
原子向量根据其存储的数据类型不同, 分为
- 逻辑向量 (logical)
- 整数向量 (integer)
- 数值向量 (numeric)
- 字符向量 (character)
以及两种不常见的类型
- 原始向量 (raw)
- 复数向量 (complex)
创建
原子向量通常用 c() 创建 (combine 的缩写):
实际上 c() 的本意是连接多个向量, 上述例子中实际是连接了多个长度为 1 的向量 (标量).
一些便捷函数可以快速创建具有特定规律的数值类向量:
取子集
可以使用另一个向量作为索引取得向量的子集. R 中使用 [] 对向量取子集, 支持三种索引:
正数索引
负数索引
逻辑索引
*R 中取向量子集的 [] 也是一个函数:
相互转换
不同原子向量可以通过 as.*() 函数族转换, 如:
对于直观上不可相互转换的类型, 强行转换会产生 NA 值:
列表
与原子向量不同, 列表的元素可以是任意类型的 R object.
创建
可以使用 list() 创建列表
类似地, 可以用 c() 合并多个列表
取子集
对列表取子集操作分为两种
[]取出子列表这与原子向量的
[]索引类似, 支持前述各种索引, 取子集后对象保持原有类型.[[]]取出列表元素 与原子向量不同, 长度为 1 的列表并不等同于其元素. 因此 R 为取出列表元素设计了额外的索引
特殊向量
原子向量和列表统称为向量. 所有向量都具有三个基本属性:
type: 存储的数据类型
length: 长度
attributes: 属性/元数据 普通的原子向量/列表无额外 attributes
若对向量添加特定的 attributes, 可以使其具有额外的性质. 以下介绍常见的 attributes.
命名向量
若在创建向量时使用命名参数, 其会拥有 names 属性
具有 names 属性的向量可以使用 name 取子集
矩阵
矩阵本质是具有 dims 属性的向量.
可以用 matrix 创建矩阵:
矩阵额外支持二维索引 (分别指定子集所在的行和列):
因子
因子是 R 中用于表示分类变量 (categorical variable) 的特殊向量类型. 本质是一个带有 levels 和 class="factor" 属性的整数向量.
可以用 factor 创建因子:
数据框
数据框是 R 中最常见的数据结构之一, 通常每一行表示一个样本, 每一列表示一个特征. 本质是一个带有 names, row.names 和 class="data.frame" 属性, 所有元素都是等长向量的列表.
可以用 data.frame 创建数据框:
作为和矩阵一样的二维结构, 数据框也额外支持二维索引:
在 2026 年, R 自带的 data.frame 类型已经有更加现代化的替代品 (如 tibble, data.table). 不过对 data.frame 的基础操作同样适用于这些新的数据框类型.
基本语法
变量命名与赋值
R 中使用 <- 给变量赋值. R 的基本变量命名规则如下:
- 不能以数字开头
- 不能包含空格或特殊符号 (如 @, #, $ 等)
- 不能使用保留字 (如
for,if)
使用反引号可以强制让引号内的字符作为一个 name, 打破上述一切规则
控制流
if条件控制 基本语法为if (condition) expression else alternative_expressionif有返回值 (返回 expression 部分):for循环 基本语法为for (variable in sequence) expression
函数
在 R 中创建函数的语法为 function(arg_list) expression 或 \(arg_list) expression, 其将返回一个 closure 类型的值:
参数可以有默认值, 且具有惰性求值机制:
此外, 存在可变长参数 ..., 通常用于转发不定数量的参数给其他函数
Hadley 的 Advanced R 中总结了 base R 中常用的函数.
源代码组织
source
项目太大时, 通常会将不同用途的代码分散在多个 R 文件中, 并互相调用. source 用于运行其他 R 文件中的代码:
R package
另一种组织 R 代码的方式是将代码放入一个 R 包. R 之所以好用也是因为存在众多 R 包.
我们重点关注如何使用别人的 R 包. 可以使用 library() 来加载本地已安装的 R 包, 之后可以使用包里的全部函数
由于 R 缺乏从包中选择性导出函数的机制, 当仅用到包里的几个函数时, 导入整个包并不明智 (引发命名冲突等). 此时我们可以使用 :: 访问包中的特定函数:
与 :: 类似的是 :::, 其可强行访问包中没有被作者导出的对象, 在查看包中的代码细节时很有用.