介绍了 R 语言中的内置基础数据结构。
R 的基础数据结构可以概括为:
相同元素 | 不同元素 | |
---|---|---|
一维(1d) | Atomic vector | List |
二维(2d) | Matrix | Data frame |
多维(nd) | Array |
R 实际上是没有标量,或者 0 维数据结构的。那些所谓的标量其实是长度为 1 的向量。
R 的一维数据结构
R 语言中的一维数据结构向量(vector)有两种类型:atomic vector 和 list,它们有三个属性:
typeof()
length()
attributes()
这两者的区别是,atomic vector 所有元素相同种类,list 中的元素可以不同种类。
注意:is.vector(x)
并不能检查 x
是不是 vector,最好使用 is.atomic(x) || is.list(x)
。
Atomic vectors
- 四种常见类型:logical, integer, double 和 character
- 两种少见类型:complex 和 raw
atomic vectors 使用 c()
来创建(c
是 combine 的简写)。
int_vec <- c(1L, 2L, 5L)
dbl_vec <- c(1.2, 2, 3.4)
log_vec <- c(TRUE, FALSE)
cha_vec <- c('Li', 'Wang', 'Wu')
使用 is.integer()
, is.double()
, is.logical()
, is.character()
来判断各自的类型,想判断是否为 atomic vector,使用 is.atomic()
。对于 integer
和 double
类型的,is.numeric()
均会返回 TRUE
。
由于 atomic vectors 要保证元素类型一样,所以会自动进行类型转换。如数值型和字符型在一起会转换为字符型,TRUE
和 FALSE
会自动转换为 1
和 0
。
Lists
list 数据结构中可以保存不同类型的数据。使用 is.list()
来检查是否为 list,使用 as.list()
把变量转换为 list,使用 unlist()
把 list 转换为 atomic vector。
疑问:为什么可以使用 unlist()
而不用 as.vector()
来将列表转换为向量?查阅网上的资料,为什么大家喜欢写 as.vector(unlist(list_a))
?
特性(attribute)
所有对象都可以有任意特性,用来保存一些关于对象的额外信息。
使用 attr()
获得单独的一个特性,或者使用 attributes()
来获得所有特性,后者获得的是一个列表。
y <- 1:10
attr(y, "my_attribute") <- "This is a vector"
attr(y, "my_attribute")
str(attributes(y))
使用 structure()
可以直接生成一个含有特性的对象:
structure(1:10, my_attribute="this is a vector")
当更改 vector 时,会有三个很重要的特性不会丢失:
- name,使用
name(x)
获取 - dimensions,使用
dim(x)
获取 - class,使用
class(x)
获取
Names
可以通过三种方式命名一个 atomic vector 变量:
- 创建时命名:
x <- c(a=1, b=2, c=3)
- 设置
names
属性:x2 <- 1:3; names(x2) <- c('a', 'b', 'c')
- 修改另一个 vector 得到:
x3 <- setNames(1:3, c('a', 'b', 'c'))
不需要所有值都有名字,如果不对其进行命名,names(x)
会得到 NULL
。想要移除 vector 的名字,使用 unname(x)
或 names(x) <- NULL
。
Factors
factor 是一种特殊的 vector,里面的元素只能是预先定义好的值,专门用来描述分类变量。它基于 vector,但额外有两个属性:class
和 levels
,使用 table
可以快速查看各组的频数:
x <- factor(c('M', 'F', 'F', 'M'))
class(x) # "factor"
levels(x) # "F" "M"
table(x)
# x
# F M
# 2 2
很多加载数据的函数会把字符型的变量自动转化为 factor,设置参数 stringsAsFactors = FALSE
来制止转化行为。很多函数会把 factor 当做是 integer 类型的,会带来很多错误。如果想用 factor 原本的元素,先用 as.character()
把它转化为 character 型。
matrix 和 array
array 可以存放多维数据,matrix 只能是二维,是一种特殊的 array。
创建 array 和 matrix:
m <- matrix(1:6, ncol = 3, nrow = 2)
a <- array(1:12, dim=c(2, 3, 2))
c <- 1:6
dim(c) <- c(2, 3)
有两类属性:
- 长度和维度:
length()
,dim()
,nrow()
,ncol()
- 命名:
rownames()
,colnames()
,dimnames()
还可以使用 rbind()
和 cbinid()
来生成矩阵。转置 matrix 使用 t()
,转置 array 使用 aperm()
。
Data frame
Data frame 本质上是一个由 vector 构成的 list 的二维数据结构,所以它兼具 list 和 matrix 的一些属性,如 names()
, colnames()
, rownames()
, length()
,
使用 data.frame()
创建一个 Data frame:
df <- data.frame(
x = 1:5,
y = c("a", "b", "c", "d", "e"),
stringsAsFactors = FALSE
)
默认会把 character 型的 atomic vector 转换为 factor,需要参数 stringsAsFactors=FALSE
来禁止这一行为。
检查和转换也很简单,和之前介绍的完全配套:is.data.frame()
,as.data.frame()
。
可以使用 rbind()
和 cbind()
来对 data frame 进行合并,但要注意的是合并时对应的行和列必须配套。
如果你把 list 或者 matrix 传入 data.frame()
中,想构建一列是 list 或者 matrix,它会报错。这时可以采用两种方法:
- 使用
cbind()
将已有的 data frame 与之合并 - 还有就是使用
I()
:data.frame(x=1:3, y=I(list(1:2, "a", FALSE))
另外还有个很有趣的一点是:使用 df[FALSE, ]
和 df[, FALSE]
可以分别得到 0 行的和 0 列的 data frame。