R 语言基础数据结构

介绍了 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()。对于 integerdouble 类型的,is.numeric() 均会返回 TRUE

由于 atomic vectors 要保证元素类型一样,所以会自动进行类型转换。如数值型和字符型在一起会转换为字符型,TRUEFALSE 会自动转换为 10

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,但额外有两个属性:classlevels,使用 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。