向量是 R 中构建对象的基础数据结构,绝大部分函数和自定义函数都会使用向量。
基础概念
R 中的向量主要有两种类型:
- 原子型向量:由同种数据类型构成的向量,依据所含元素的类型,可以将其分为六种类型:逻辑型、整型、双精度型、字符型、复数型和原始型。整型和双精度型又被统称为数值型
- 列表:与原子型向量类似,但不要求内部元素必须同型。并且列表中可以包含其他列表,因此也被称为递归向量
此外,还存在 NULL 这一特殊的类型,其本身也是一种对象。NULL 作为对象是指一个空向量,通常是指长度为 0 的向量
每个向量都有两个关键属性:
- 类型:可以使用
typeof()
函数来确定向量的类型 - 长度:可以使用
length()
函数来确定向量的长度
除此之外,还可以向向量中添加额外的、任意的元数据(称为特性)。特性可以用来创建扩展向量,最常见的扩展向量有:
- 基于整形向量构建的因子
- 基于数值型向量构建的日期和日期时间
- 基于列表构建的数据框和 tibble
原子型向量分类
逻辑型向量
逻辑型向量中的取值有三种:FALSE
、TURE
或 NA
。
数值型向量
整型与双精度型向量统称为数值型向量。对应的可选取值是实数和整数。整数在 R 中默认是双精度型的,要想以整型定义数据,可以在数字后加字母 L 来表示:
1 | > typeof(1) |
由于浮点误差的存在,双精度数值是估计值而不是精确值
整型数据有 1 个特殊值 NA ,双精度型数据有 4 个特殊值 NA 、NaN 、Inf 和 -Inf 。可以使用以下函数进行检测:
0 | Inf (-Inf) | NA | NaN | |
---|---|---|---|---|
is.finite() | T | F | F | F |
is.infinite() | F | T | F | F |
is.na() | F | F | T | T |
is.nan() | F | F | F | T |
字符型向量
字符型向量中的每个元素都是一个字符串,字符串理论上可以包含任意数量的数据。
R 中字符串存在于全局字符串池中,意味着每个唯一的字符串在内存中只保存一次
缺失值
每种类型的原子向量都有相应的缺失值 NA 。
原子型向量使用
强制转换
由于部分值在不同的数据类型中存在着对应关系,因此可以通过强制转换将数据转换为可用的其它类型。强制转换一般有两种状况:显式强制转换和隐式强制转换。
显式强制转换
可以使用以下函数将数据显式强制转换为其它类型:
函数 | 作用 |
---|---|
as.logical() | 将数据转换为逻辑型 |
as.integer() | 将数据转换为整型 |
as.double() | 将数据转换为双精度型 |
as.character() | 将数据转换为字符型 |
隐式强制转换
当环境中需要使用的数据类型与所给的数据类型不一致时,R 会尝试将其转换为相应的可用类型,这个过程被称为隐式强制转换。常见的状况有:
- 数值环境中的逻辑向量:TRUE 会转换为 1 ,FALSE 会转换为 0
- 逻辑环境中的数值向量:1 会转换为 TRUE ,0 会转换为 FALSE
- 双精度环境中的整形向量:整型数值会转换为与之相等的双精度数值
向量类型检验
获得向量类型最常用的方法便是使用 typeof()
函数。此外,还可以使用检验函数,通过返回值为 TRUE 或 FALSE 来判断向量是否是指定的类型。在 purrr
包中,存在着以下检验函数:
逻辑型 | 整型 | 双精度型 | 字符型 | 列表 | |
---|---|---|---|---|---|
is_logical() | T | F | F | F | F |
is_integer() | F | T | F | F | F |
is_double() | F | F | T | F | F |
is_numeric() | F | T | T | F | F |
is_character() | F | F | F | T | F |
is_atomic() | T | T | T | T | F |
is_list() | F | F | F | F | T |
is_vector() | T | T | T | T | T |
以上函数还有着相应的标量检验函数,is_*()
的对应函数为 is_scalar_*()
函数。其作用除了用来检验输入参数是否为指定类型,还用来判断该参数是否长度为 1 。
标量与循环规则
与类型强制转换类似,R 中还存在着另一种强制转换:长度强制转换。这种转换也被称为向量循环,因为 R 会将长度不同但环境需要长度相同的向量的较短一方重复(或循环)到与较长的向量相同的长度。但这要求较长向量的长度是较短向量的长度的整数倍,也因此向量与“标量”(在 R 中即为长度为 1 的向量)的混合使用是最常见的。也因此,R 中的大量内置函数向量化的。
由于向量循环这一过程在 R 中类似于隐式强制转换,因此部分包(例如 tidyverse
)中的向量化函数在遇到向量循环时会给出错误信息。因此可以使用 rep()
函数来实现长度显式强制转换。
向量命名
除了向量本身可以命名之外,向量内部的元素也可以命名:
1 | > c(x = 1, y = 2, z = 3) |
向量取子集
可以使用中括号包裹 []
来实现向量索引,进而达成向量取子集。取子集的方式有以下几种:
- 整数索引
- 正整数索引
- 负整数索引
- 零索引
- 逻辑索引
- 名称索引
- 全索引:
x[]
列表(递归向量)
列表这一形式是基于原子型向量之上的,因此大部分不与向量冲突的特性在列表中仍可使用。如:强制转换(类型和长度)、命名、取子集等。
向量是使用 c()
函数构建的,而列表则是使用 list()
函数构建的。与原子型向量不同,列表中不仅可以包含不同类型的数据,还可以包含列表(即列表嵌套)。
可以使用 str()
函数来列出列表结构。
列表取子集主要有 3 种方式:
- 使用
[
提取子列表。这种方式的结果是一个列表 - 使用
[[
提取单个元素。这种方式的结果是列表删除一个层次等级的元素 - 使用
$
提取单个元素。和上一种类似,只不过该方法对命名元素提取时需要用元素名而不是元素名的字符串
特性
任何向量都可以通过特性来附加任意元数据,相当于附加在对象上的向量命名列表。可以使用 attr()
函数来读取和设置单个特性值,也可以使用 attributes()
函数同时查看所有特性值。
在 R 对象的所有特性中,有 3 种特别重要的特性:
- 名称:用于命名向量元素
- 维度:用于实现向量的类矩阵或类数组操作
- 类:用于实现面向对象的 S3 系统
扩展向量
除了原子型向量和列表等基础向量,还有着使用基础向量构建的较复杂的向量,一般称之为扩展向量,并且具有类等附加特性。常见的扩展向量有以下几种。
因子
因子是设计用来表示分类数据的,只能在固定集合中取值。其在整型向量的基础上添加了水平(levels)特性。
日期和日期时间
R 中的日期是由数值型向量改造而成,表示从 1970 年 1 月 1 日开始的天数。
R 中的日期时间是带有 POSIXct 类的数值型向量,表示从 1970 年 1 月 1 日开始的秒数。
R 中还有一种日期时间是 POSIXlt 类的命名列表。
时间类的扩展向量基本都带有时区或类似时区的特性 tzone
。
tibble
tibble
是扩展的列表,有 3 个类:tbl_df
、tbl
和data.frame
。并含有 2 个特性:names
和 row.names
。