现在是 2020 年 1 月 12 日:
参考链接:
- Merging a lot of data.frames [duplicate]
- merge.html
当列名相同时
第一种方法:
df1 = data.frame(id = c('1','73','2','10','43'),
v1 = c(1,2,3,4,5))
df1
df2 = data.frame(id = c('7','23','57','2','62','96'),
v2 = c(1,2,3,4,5,6))
df2
df3 = data.frame(id = c('23','62'),
v3 = c(1,2))
df3
Reduce(function(x, y) merge(x, y, all=TRUE),
list(df1, df2, df3))
id v1 v2 v3
1 1 1 NA NA
2 10 4 NA NA
3 2 3 4 NA
4 43 5 NA NA
5 73 2 NA NA
6 23 NA 2 1
7 57 NA 3 NA
8 62 NA 5 2
9 7 NA 1 NA
10 96 NA 6 NA
# 或者
Reduce(function(...) merge(..., all=TRUE),
list(df1, df2, df3))
# 其实上面拆开就是拆开就是
merge(merge(df1, df2, by = 'id', all = T), df3,
by = 'id', all = T)
第二种方法:
插曲:
动态图见:R 语言中 dplyr 包 jion 函数之目前我看到过的最形象的教程
inner_join(): 相当于交集
left_join():字面意思,左连接;保留 x 中的所有观测
right_join():右连接;保留 y 中的所有观测
full_join():全连接;保留 x 和 y 中的所有观测
semi_join():保留 x 表中与 y 表中的观测相匹配的所有观测
anti_join():丢弃 x 表中与 y 表中的观测相匹配的所有观测。
library(tidyverse)
df1 %>%
full_join(df2, by = "id") %>%
full_join(df3, by = "id")
id v1 v2 v3
1 1 1 NA NA
2 73 2 NA NA
3 2 3 4 NA
4 10 4 NA NA
5 43 5 NA NA
6 7 NA 1 NA
7 23 NA 2 1
8 57 NA 3 NA
9 62 NA 5 2
10 96 NA 6 NA
当列名不同?
当我们所需要合并的列的列名不一样时候, 第一种方法可能就不够用了,或者说要进行修改。
但是第二种方法仍然有效
library(tidyverse)
df1 %>%
full_join(df2, by = c("id" = "id1")) %>% # id 为数据 df1 所要合并的列,id1 是 df2 所要合并的列
full_join(df3, by = c("id" = "id2"))
id v1 v2 v3
1 1 1 NA NA
2 73 2 NA NA
3 2 3 4 NA
4 10 4 NA NA
5 43 5 NA NA
6 7 NA 1 NA
7 23 NA 2 1
8 57 NA 3 NA
9 62 NA 5 2
10 96 NA 6 NA
如果我们使用 merge()
函数呢?
library(tidyverse)
merge(df1, df2, by.x = "id", by.y = "id1", all = TRUE) %>%
merge(., df3, by.x = "id", by.y = "id2", all = TRUE)
id v1 v2 v3
1 1 1 NA NA
2 10 4 NA NA
3 2 3 4 NA
4 43 5 NA NA
5 73 2 NA NA
6 23 NA 2 1
7 57 NA 3 NA
8 62 NA 5 2
9 7 NA 1 NA
10 96 NA 6 NA
# 或者不借助管道,因为都用管道符号了那直接用 full_join() 系列函数不就行了?
merge(merge(df1, df2, by.x = "id", by.y = "id1", all = TRUE), df3,
by.x = "id", by.y = "id2", all = TRUE)
id v1 v2 v3
1 1 1 NA NA
2 10 4 NA NA
3 2 3 4 NA
4 43 5 NA NA
5 73 2 NA NA
6 23 NA 2 1
7 57 NA 3 NA
8 62 NA 5 2
9 7 NA 1 NA
10 96 NA 6 NA
既然提到了数据合并,那就顺带提一下数据的 长边宽 和 宽变长
宽变长和长变宽
参考链接(请花点时间都看下):
- R mini camp: Reshape2 and Tidyr
- Pivoting data frames just got easier thanks to `pivot_wide()` and pivot_long() : 不知道为啥链接函数名改了。
宽变长
- gather()
- melt()
- pivot_longer()
# melt()
# id.vars 表示不变的列,如:id.vars = c("year", "month")
# measure.vars 表示要变的列
# variable.name 表示你分组后的 group 列名,即下面的 variable
# value.name 表示对应的值的列名
# na.rm 表示是否去除 NA 值的行
data_long <- reshape2::melt(merge_data,
measure.vars = c('v1','v2','v3'),
variable.name = "test_group",
value.name = "test_value")
data_long
id test_group test_value
1 1 v1 1
2 10 v1 4
3 2 v1 3
4 43 v1 5
5 73 v1 2
6 23 v1 NA
7 57 v1 NA
8 62 v1 NA
9 7 v1 NA
10 96 v1 NA
11 1 v2 NA
12 10 v2 NA
13 2 v2 4
14 43 v2 NA
15 73 v2 NA
16 23 v2 2
17 57 v2 3
18 62 v2 5
19 7 v2 1
20 96 v2 6
21 1 v3 NA
22 10 v3 NA
23 2 v3 NA
24 43 v3 NA
25 73 v3 NA
26 23 v3 1
27 57 v3 NA
28 62 v3 2
29 7 v3 NA
30 96 v3 NA
# gather()
# gather(data, key = "key", value = "value", ..., na.rm = FALSE,
# convert = FALSE, factor_key = FALSE)
data_long1 <- tidyr::gather(merge_data,
test_group, test_value, 要生成的新列的 group 列名和值列名
-id) # 不变的列,其他的都变,多列不变就多 -a, -b
data_long1
id test_group test_value
1 1 v1 1
2 10 v1 4
3 2 v1 3
4 43 v1 5
5 73 v1 2
6 23 v1 NA
7 57 v1 NA
8 62 v1 NA
9 7 v1 NA
10 96 v1 NA
11 1 v2 NA
12 10 v2 NA
13 2 v2 4
14 43 v2 NA
15 73 v2 NA
16 23 v2 2
17 57 v2 3
18 62 v2 5
19 7 v2 1
20 96 v2 6
21 1 v3 NA
22 10 v3 NA
23 2 v3 NA
24 43 v3 NA
25 73 v3 NA
26 23 v3 1
27 57 v3 NA
28 62 v3 2
29 7 v3 NA
30 96 v3 NA
# pivot_longer
# devtools::install_github("tidyverse/tidyr")
# library(tidyverse)
data_long1 <- data_wide %>%
tidyr::pivot_longer(cols = c("v1", "v2", "v3"), # 变的列,也就是即将合并为一列的列
names_to = "test_group", # 表示你分组后的 group 列名,即 cols 合并后的列名
values_to = "test_value") # 表示对应的值的列名
data_long1
# A tibble: 30 x 3
id test_group test_value
<fct> <chr> <dbl>
1 1 v1 1
2 1 v2 NA
3 1 v3 NA
4 10 v1 4
5 10 v2 NA
6 10 v3 NA
7 2 v1 3
8 2 v2 4
9 2 v3 NA
10 43 v1 5
# … with 20 more rows
长变宽
- spread()
- dcast()
- pivot_wider()
# dcast
# dcast(data, formula, fun.aggregate = NULL, ..., margins = NULL,
subset = NULL, fill = NULL, drop = TRUE,
value.var = guess_value(data))
# id ~ test_group:将为新的 group 列 + group 列
# fun.aggregate:可以复制数据处理处理函数功能:mean,max等等
reshape2::dcast(data_long, id ~ test_group)
id v1 v2 v3
1 1 1 NA NA
2 10 4 NA NA
3 2 3 4 NA
4 43 5 NA NA
5 73 2 NA NA
6 23 NA 2 1
7 57 NA 3 NA
8 62 NA 5 2
9 7 NA 1 NA
10 96 NA 6 NA
# spread()
# spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE, sep = NULL)
tidyr::spread(data_long1, "test_group", "test_value")
id v1 v2 v3
1 1 1 NA NA
2 10 4 NA NA
3 2 3 4 NA
4 43 5 NA NA
5 73 2 NA NA
6 23 NA 2 1
7 57 NA 3 NA
8 62 NA 5 2
9 7 NA 1 NA
10 96 NA 6 NA
# pivot_wider
data_wide <- data_long %>%
tidyverse::pivot_wider(names_from = "test_group",
values_from = "test_value")
data_wide
# A tibble: 10 x 4
id v1 v2 v3
<fct> <dbl> <dbl> <dbl>
1 1 1 NA NA
2 10 4 NA NA
3 2 3 4 NA
4 43 5 NA NA
5 73 2 NA NA
6 23 NA 2 1
7 57 NA 3 NA
8 62 NA 5 2
9 7 NA 1 NA
10 96 NA 6 NA
既然提到了上面,那么就再顺带提一下将一列分割?
参考链接: How to reshape data in R: tidyr vs reshape2
- separate()
- aggregate (): 很有用,以后补上