学习R之列表和数据框

1. 列表

1.1 创建列表

列表由 list 函数创建,且能像 c 函数那样指定内容,只需简单地用逗号分隔每个参数即可指定列表中的内容。列表中元素变量的类型不限, 可以是向量、矩阵,甚至函数。

与向量的命名类似,可以在构造列表时就给元素命名,或在构造之后使用 names 函数命名:

(a_list <- list(
    c(1, 1, 2, 5, 14, 42),
    month.abb,
    matrix(c(3, -8, 1, -3), nrow = 2),
    asin
))
>> [[1]]
>> [1]  1  1  2  5 14 42
>> 
>> [[2]]
>>  [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
>> 
>> [[3]]
>>      [,1] [,2]
>> [1,]    3    1
>> [2,]   -8   -3
>> 
>> [[4]]
>> function (x)  .Primitive("asin")

names(a_list) <- c("catalan", "months", "involutary", "arcsin")
a_list
>> $catalan
>> [1]  1  1  2  5 14 42
>> 
>> $months
>>  [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
>> 
>> $involutary
>>      [,1] [,2]
>> [1,]    3    1
>> [2,]   -8   -3
>> 
>> $arcsin
>> function (x)  .Primitive("asin")

the_same_list <- list(
    catalan = c(1, 1, 2, 5, 14, 42),
    months = month.abb,
    involutary = matrix(c(3, -8, 1, -3), nrow = 2),
    arcsin = asin
)

列表与向量一样也有长度,其长度是它顶层元素的数目。
length(a_list)
>> [1] 4
1.2 列表的索引

与向量类似,可通过方括号 [ ]、正或负的下标数字、元素名称或逻辑索引这四种方法访问列表中的元素,以下四行代码的结果相同:

l <- list(
    first  = 1,
    second = 2,
    third  = list(
        alpha = 3.1,
        beta = 3.2 
    )
)

l[1:2]
>> $first
>> [1] 1
>> 
>> $second
>> [1] 2

l[-3]
>> $first
>> [1] 1
>> 
>> $second
>> [1] 2

l[c("first", "second")]
>> $first
>> [1] 1
>> 
>> $second
>> [1] 2

l[c(TRUE, TRUE, FALSE)]
>> $first
>> [1] 1
>> 
>> $second
>> [1] 2

以上索引操作的结果仍然是一个列表,但有时需要访问列表元素中的内容,可以使用双方括号 [[ ]], 或指定该元素的名称字符串来获取元素中的内容,对于列表中的命名元素,使用美元符号运算符 $ 与之等价。

is.list 函数可以判断变量是否为列表,如果是列表将返回 TRUE,否则返回 FALSE。

l[[1]]
>> [1] 1

l[["first"]]
>> [1] 1

l$first
>> [1] 1

is.list(l[1])
>> [1] TRUE

is.list(l[[1]])
>> [1] FALSE

也可以通过嵌套方括号来访问嵌套的元素。
l[["third"]]["beta"]
>> $beta
>> [1] 3.2

l[["third"]][["beta"]]
>> [1] 3.2
1.3 列表与向量的转换

向量可使用函数 as.list 函数来转换成列表,所创建的可见列表与向量中元素的值一一对应:

busy_beaver <- c(1, 6, 21, 107)
as.list(busy_beaver)
>> [[1]]
>> [1] 1
>> 
>> [[2]]
>> [1] 6
>> 
>> [[3]]
>> [1] 21
>> 
>> [[4]]
>> [1] 107
1.4 NULL值

NULL 是个特殊值,它表示一个空的变量,最常用于列表中,不过也会出现在数据框和函数参数中。

在创建列表时,你可能会想指定一个元素,表明它必须存在但没有赋值,这时可以用 NULL 来表示:

(person <- list(
       name = "Jack",
       age = 28,
       sex = "male",
       profession = NULL
    )
)
>> $name
>> [1] "Jack"
>> 
>> $age
>> [1] 28
>> 
>> $sex
>> [1] "male"
>> 
>> $profession
>> NULL

理解 NULL 和特殊的缺失值 NA 之间的区别非常重要。最大的区别是,NA 是一个标量值,而 NULL 不会占用任何空间,它的长度为零。

可以使用函数 is.null 来判断变量是否为 NULL 值,缺失值不是 NULL。

length(NULL)
>> [1] 0

length(NA)
>> [1] 1

is.null(NULL)
>> [1] TRUE

is.null(NA)
>> [1] FALSE

2. 数据框

2.1 创建数据框

数据框用于存储类似电子表格的数据,每列的数据类型可与其他列不同,但在同一列中的元素类型必须相同。

可以通过给 row.names 传入一个向量来为每行命名,如果不指定的话,行号默认是从 1 开始递增的数字。

# 不指定行名称
(a_data_frame <- data.frame(
        x = letters[1:5],
        y = rnorm(5),
        z = runif(5) > 0.5
))
>>   x           y     z
>> 1 a -0.55491035  TRUE
>> 2 b -0.49873077  TRUE
>> 3 c  0.71456065  TRUE
>> 4 d -0.01201503  TRUE
>> 5 e -0.33923612 FALSE

# 指定行名称
data.frame(
       x = letters[1:5],
       y = rnorm(5),
       z = runif(5) > 0.5,
       row.names = c("Jackie", "Tito", "Jermaine", "Marlon", "Michael")
)
>>          x          y     z
>> Jackie   a -0.7869658 FALSE
>> Tito     b  1.3779004 FALSE
>> Jermaine c  0.6656291  TRUE
>> Marlon   d  0.1054912  TRUE
>> Michael  e  1.0801238  TRUE

像矩阵一样,维度的名称可以使用 dimnames 来获取,同样地,也可以使用 rownames 和 colnames 分别获取或置行和列的名称。

事实上,几乎所有用于矩阵的函数亦可用在数据框上,例如,nrow、ncol 和 dim 函数的使用也与矩阵一样。

dimnames(a_data_frame)
>> [[1]]
>> [1] "1" "2" "3" "4" "5"
>> 
>> [[2]]
>> [1] "x" "y" "z"

rownames(a_data_frame)
>> [1] "1" "2" "3" "4" "5"

colnames(a_data_frame)
>> [1] "x" "y" "z"

dim(a_data_frame)
>> [1] 5 3

nrow(a_data_frame)
>> [1] 5

ncol(a_data_frame)
>> [1] 3
2.2 数据框的索引

数据框的索引与矩阵的索引方式类似,可使用四种不同的向量索引 (正整数、负整数、逻辑值和字符),如选择数据框中前两列的第二个和第三个元素:

a_data_frame[2:3, -3]
>>   x          y
>> 2 b -0.4987308
>> 3 c  0.7145607

a_data_frame[c(FALSE, TRUE, TRUE, FALSE, FALSE), c("x", "y")]
>>   x          y
>> 2 b -0.4987308
>> 3 c  0.7145607

如果只需选择一列,也可以使用列表样式的索引 (带有正整数或名称的双方括号,或者带有名称的美元符号运算符),如选择第一列中的第二个和第三个元素:
a_data_frame$x[2:3]
>> [1] b c
>> Levels: a b c d e

a_data_frame[[1]][2:3]
>> [1] b c
>> Levels: a b c d e

a_data_frame[['x']][2:3]
>> [1] b c
>> Levels: a b c d e

如果需要给列加上条件来得到一个数据框子集,使用的语法会有点冗长,其中 & 表示多个条件同时满足,| 表示满足其中的一个条件即可。

subset 函数能做同样的事情且更简洁,需传入三个参数:一个数据框,一个行的条件逻辑向量,以及一个需要保留的名字向量,如果最后一个参数省略,则将保留所有列。

# 单个条件
a_data_frame[ a_data_frame$y > 0, c("x", "y")]
>>   x         y
>> 3 c 0.7145607

# 同时满足两个条件 &
a_data_frame[ a_data_frame$y < 0 & a_data_frame$x %in% c("b", "c"), c("x", "y")]
>>   x          y
>> 2 b -0.4987308

# 至少满足一个条件 | 
a_data_frame[ a_data_frame$y > 0 | a_data_frame$z == TRUE, c("x", "y", "z")]
>>   x           y    z
>> 1 a -0.55491035 TRUE
>> 2 b -0.49873077 TRUE
>> 3 c  0.71456065 TRUE
>> 4 d -0.01201503 TRUE

# 使用 subset 函数实现
subset(a_data_frame, y > 0, c("x", "y"))
>>   x         y
>> 3 c 0.7145607

subset(a_data_frame, y < 0 & x %in% c("b", "c"), c("x", "y"))
>>   x          y
>> 2 b -0.4987308

subset(a_data_frame, y > 0 | z == TRUE, c("x", "y", "z"))
>>   x           y    z
>> 1 a -0.55491035 TRUE
>> 2 b -0.49873077 TRUE
>> 3 c  0.71456065 TRUE
>> 4 d -0.01201503 TRUE
2.3 数据框的基本操作

如果两个数据框的大小一致,也可使用 cbind 和 rbind 把它们合并起来,但并不会对列名作重复性检查,所以使用时要注意。

another_data_frame <- data.frame(
    z = rlnorm(5),
    y = sample(5),
    x = letters[3:7]
)

# 纵向合并
rbind(a_data_frame, another_data_frame)
>>    x           y         z
>> 1  a -0.55491035 1.0000000
>> 2  b -0.49873077 1.0000000
>> 3  c  0.71456065 1.0000000
>> 4  d -0.01201503 1.0000000
>> 5  e -0.33923612 0.0000000
>> 6  c  5.00000000 0.7193025
>> 7  d  4.00000000 0.6850233
>> 8  e  3.00000000 0.3708307
>> 9  f  1.00000000 2.8386495
>> 10 g  2.00000000 1.7468346

# 横向合并
cbind(a_data_frame, another_data_frame)
>>   x           y     z         z y x
>> 1 a -0.55491035  TRUE 0.7193025 5 c
>> 2 b -0.49873077  TRUE 0.6850233 4 d
>> 3 c  0.71456065  TRUE 0.3708307 3 e
>> 4 d -0.01201503  TRUE 2.8386495 1 f
>> 5 e -0.33923612 FALSE 1.7468346 2 g

当两个数据框有相同的列时,可使用 merge 函数合并,连接时需要指定包含键值的列以作匹配。

merge 函数支持以下四种类型的数据合并:

  • inner join: 内连接,仅返回两数据框中匹配的行,参数为:all = FALSE
  • full outer join: 全连接,返回两数据框中的所有行,参数为:all = TRUE
  • left outer join: 左连接,返回 x 数据框中所有行以及和 y 数据框中匹配的行,参数为:all.x = TRUE
  • right outer join: 右连接,返回 y 数据框中所有行以及和 x 数据框匹配的行,参数为:all.y = TRUE
# 内连接
merge(a_data_frame, another_data_frame, by = "x")
>>   x         y.x   z.x       z.y y.y
>> 1 c  0.71456065  TRUE 0.7193025   5
>> 2 d -0.01201503  TRUE 0.6850233   4
>> 3 e -0.33923612 FALSE 0.3708307   3

# 全连接
merge(a_data_frame, another_data_frame, by = "x", all = TRUE)
>>   x         y.x   z.x       z.y y.y
>> 1 a -0.55491035  TRUE        NA  NA
>> 2 b -0.49873077  TRUE        NA  NA
>> 3 c  0.71456065  TRUE 0.7193025   5
>> 4 d -0.01201503  TRUE 0.6850233   4
>> 5 e -0.33923612 FALSE 0.3708307   3
>> 6 f          NA    NA 2.8386495   1
>> 7 g          NA    NA 1.7468346   2

# 左连接
merge(a_data_frame, another_data_frame, by = "x", all.x = TRUE)
>>   x         y.x   z.x       z.y y.y
>> 1 a -0.55491035  TRUE        NA  NA
>> 2 b -0.49873077  TRUE        NA  NA
>> 3 c  0.71456065  TRUE 0.7193025   5
>> 4 d -0.01201503  TRUE 0.6850233   4
>> 5 e -0.33923612 FALSE 0.3708307   3

# 右连接
merge(a_data_frame, another_data_frame, by = "x", all.y = TRUE)
>>   x         y.x   z.x       z.y y.y
>> 1 c  0.71456065  TRUE 0.7193025   5
>> 2 d -0.01201503  TRUE 0.6850233   4
>> 3 e -0.33923612 FALSE 0.3708307   3
>> 4 f          NA    NA 2.8386495   1
>> 5 g          NA    NA 1.7468346   2

操作数据框是一个很大的话题,我们将在之后的章节中继续深入探讨。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数分进阶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值