我有两个数据帧/元组。第一个是具有描述这些国家的若干变量的国家列表。此数据框包含多个缺失值。缺少哪些变量取决于国家。
library(tidyverse)
df1<-data.frame(id=1:10,
country=c("A","A","A","A","B","B","C","C","C","C"),
var1=c(NA,NA,NA,NA,1,1,2,1,2,1),
var2=c(1,1,2,2,NA,NA,1,2,2,2),
var3=c("NO","YES","NO","YES","NO","NO",NA,NA,NA,NA),
var4=c(NA,NA,NA,NA,"NO","NO",NA,NA,NA,NA)
)
df1<-as_tibble(df1)
然后我有第二个数据框(df2)我想加入第一个表:
df2<-data.frame(id=c(2,3,5,6,7,8,9,10),
country=c("A", "A", "B", "B", "C", "C", "C", "C"),
var1=c(1,2,2,2,2,1,2,1),
var2=c(2,1,1,1,1,2,1,1),
var3=c("NO","NO", "YES", "NO", "NO", "NO", "YES","NO"),
var4=c("YES", "NO", "NO", "YES", "YES", "NO", "NO", "YES")
)
df2<-as_tibble(df2)
最后,我想要的是第一个使用第二个数据帧完成缺失值的数据帧。所以我想使用id
- 变量加入两个表。但是,此连接应仅“部分”,因为缺少哪些变量取决于国家/地区:例如对于国家/地区“A”,只应填写变量var1
和var4
。在国家/地区“C”中,应从df2填写变量var3
和var4
。 df1包含的案例多于df2。
有谁能告诉我哪个是解决这个问题的最佳解决方案?
非常感谢!
答案 0 :(得分:3)
这是提供数据的一种潜在解决方案。我在两个数据框中添加了stringsAsFactors = FALSE
。看到这些数据,我想你会想要绑定它们而不是加入它们。绑定数据后,我按id
,country
和index
对其进行了排序。 index
表示来自哪个数据帧数据。然后,我按id
和country
创建了群组。对于具有两行的组,第一行具有您要填充的目标NA。这些NA保留在四列中(即var1-4
)。我在na.locf()
包中应用zoo
来执行填充过程。对于每个组,第一行来自df1
,您希望保留它们。我选择在这里使用distinct()
。但slice(1)
是另一种选择。
df1 <- data.frame(id=1:10,
country=c("A","A","A","A","B","B","C","C","C","C"),
var1=c(NA,NA,NA,NA,1,1,2,1,2,1),
var2=c(1,1,2,2,NA,NA,1,2,2,2),
var3=c("NO","YES","NO","YES","NO","NO",NA,NA,NA,NA),
var4=c(NA,NA,NA,NA,"NO","NO",NA,NA,NA,NA),
stringsAsFactors = F)
df2 <- data.frame(id=c(2,3,5,6,7,8,9,10),
country=c("A", "A", "B", "B", "C", "C", "C", "C"),
var1=c(1,2,2,2,2,1,2,1),
var2=c(2,1,1,1,1,2,1,1),
var3=c("NO","NO", "YES", "NO", "NO", "NO", "YES","NO"),
var4=c("YES", "NO", "NO", "YES", "YES", "NO", "NO", "YES"),
stringsAsFactors = F)
library(dplyr)
library(zoo)
bind_rows(df1, df2, .id = "index") %>%
arrange(id, country, index) %>%
group_by(id, country) %>%
mutate_at(vars(var1:var4), funs(if(n() > 1) {na.locf(., fromLast = TRUE)} else {.})) %>%
distinct(id, .keep_all = TRUE) %>%
select(-index)
id country var1 var2 var3 var4
<dbl> <chr> <dbl> <dbl> <chr> <chr>
1 1.00 A NA 1.00 NO <NA>
2 2.00 A 1.00 1.00 YES YES
3 3.00 A 2.00 2.00 NO NO
4 4.00 A NA 2.00 YES <NA>
5 5.00 B 1.00 1.00 NO NO
6 6.00 B 1.00 1.00 NO NO
7 7.00 C 2.00 1.00 NO YES
8 8.00 C 1.00 2.00 NO NO
9 9.00 C 2.00 2.00 YES NO
10 10.0 C 1.00 2.00 NO YES
答案 1 :(得分:1)
更新了保留类型但需要一些文字代码的建议。
rename_at(df2, vars(starts_with("var")), ~ paste0("new", .)) %>%
select(-country) %>%
right_join(df1, by = "id") %>%
mutate(
var1 = if_else(is.na(var1), newvar1, var1),
var2 = if_else(is.na(var2), newvar2, var2),
var3 = if_else(is.na(var3), newvar3, var3),
var4 = if_else(is.na(var4), newvar4, var4)
) %>%
select(-starts_with("newvar"))
使用的另一种方法是在相关列名称上循环(在管道外部):
df3 <- rename_at(df2, vars(starts_with("var")), ~ paste0("new", .)) %>%
select(-country) %>%
right_join(df1, by = "id")
for (v in colnames(df1)[ grepl("^var", colnames(df1)) ]) {
df3[[v]] <- if_else(is.na(df3[[v]]), df3[[ paste0("new", v) ]], df3[[v]])
}
select(df3, -starts_with("newvar"))
编辑:oops,刚刚意识到&#34; var&#34;列是混合类型。如果所有内容都相同,则以下答案有效,但不在此处。使用前面的代码会保留类型。
如果你重命名&#34; var&#34; df2
中的变量,您可以对df1
&#34; var&#34;进行并排比较和重新分配。变量。一种方法可能是使用dplyr::mutate_if
和starts_with("var")
,但这对您的数据提出了可能过于严格的要求。
我建议使用中间体&#34; tall&#34; (与#34;广泛的#34;)格式,以便var1
到var4
进行广义处理;这样,如果你真的有更多,你就不需要遍历每个变量。
假设:df2$id
应该足够,id$country
是不必要的。
library(dplyr)
library(tidyr)
df1<-data_frame(id=1:10,
country=c("A","A","A","A","B","B","C","C","C","C"),
var1=c(NA,NA,NA,NA,1,1,2,1,2,1),
var2=c(1,1,2,2,NA,NA,1,2,2,2),
var3=c("NO","YES","NO","YES","NO","NO",NA,NA,NA,NA),
var4=c(NA,NA,NA,NA,"NO","NO",NA,NA,NA,NA)
)
df2<-data_frame(id=c(2,3,5,6,7,8,9,10),
country=c("A", "A", "B", "B", "C", "C", "C", "C"),
var1=c(1,2,2,2,2,1,2,1),
var2=c(2,1,1,1,1,2,1,1),
var3=c("NO","NO", "YES", "NO", "NO", "NO", "YES","NO"),
var4=c("YES", "NO", "NO", "YES", "YES", "NO", "NO", "YES")
)
select(df2, -country) %>%
gather(k, newv, -id) %>%
right_join(gather(df1, k, v, -id, -country), by = c("id", "k")) %>%
mutate(v = ifelse(is.na(v), newv, v)) %>%
select(-newv) %>%
spread(k, v)
# # A tibble: 10 × 6
# id country var1 var2 var3 var4
# * <dbl> <chr> <chr> <chr> <chr> <chr>
# 1 1 A <NA> 1 NO <NA>
# 2 2 A 1 1 YES YES
# 3 3 A 2 2 NO NO
# 4 4 A <NA> 2 YES <NA>
# 5 5 B 1 1 NO NO
# 6 6 B 1 1 NO NO
# 7 7 C 2 1 NO YES
# 8 8 C 1 2 NO NO
# 9 9 C 2 2 YES NO
# 10 10 C 1 2 NO YES