我想匹配R中的两个相似数据帧。两个df都有部分相同的变量和一个键(id),其中包含缺失值:
library(tidyverse)
df1 <- as_tibble(list(id = seq(1:6),
v1 = c(1, 0, NA, 1, 0, NA),
v2 = c(NA, NA, 0, 0, 1, NA),
v3 = c(1, 0 , 1, 1, 1, NA)))
df1
# A tibble: 6 x 4
id v1 v2 v3
<int> <dbl> <dbl> <dbl>
1 1 1 NA 1
2 2 0 NA 0
3 3 NA 0 1
4 4 1 0 1
5 5 0 1 1
6 6 NA NA NA
df2 <- as_tibble(list(id = seq(1:6),
v1 = c(1, NA, 0, 1, 0, 1),
v2 = c(1, 0, 0, NA, 1, 1),
v4 = c(0, 1, 0, NA, NA, NA)))
df2
# A tibble: 6 x 4
id v1 v2 v4
<int> <dbl> <dbl> <dbl>
1 1 1 1 0
2 2 NA 0 1
3 3 0 0 0
4 4 1 NA NA
5 5 0 1 NA
6 6 1 1 NA
我想将它们合并为一个如下所示的df:
id v1 v2 v3 v4
<int> <dbl> <dbl> <dbl> <dbl>
1 1 1 1 1 0
2 2 0 0 0 1
3 3 0 0 1 0
4 4 1 0 1 NA
5 5 0 1 1 NA
6 6 1 1 NA NA
到目前为止,我已经尝试过dplyr的各种联接,但是不知何故,我无法理解。
答案 0 :(得分:2)
更好的答案,与我的第一个相比:
bind_rows(df1, df2) %>%
group_by(id) %>%
summarise_all(~ coalesce(.[1], .[2]))
## A tibble: 6 x 5
# id v1 v2 v3 v4
# <int> <dbl> <dbl> <dbl> <dbl>
# 1 1 1 1 1 0
# 2 2 0 0 0 1
# 3 3 0 0 1 0
# 4 4 1 0 1 NA
# 5 5 0 1 1 NA
# 6 6 1 1 NA NA
答案 1 :(得分:1)
使用通用名称拆分后,我们可以在共享列上使用dplyr::coalesce
。然后 map 循环遍历具有多于一列的dfs,并使用mutate
coalesce
library(dplyr)
library(purrr)
df1 %>% left_join(df2, by='id') %>%
split.default(gsub('.[xy]','',names(.))) %>%
map_dfc(~if(ncol(.x)==1) .x else
mutate(.x, !!sym(gsub('.x','',names(.x)[1])):=coalesce(!!!syms(names(.x))))) %>%
select(-contains('.'))
# A tibble: 6 x 5
id v1 v2 v3 v4
<int> <dbl> <dbl> <dbl> <dbl>
1 1 1 1 1 0
2 2 0 0 0 1
3 3 0 0 1 0
4 4 1 0 1 NA
5 5 0 1 1 NA
6 6 1 1 NA NA
这里有一个简单的示例,说明sym
和syms
对每个包含.x和.y列的变量的作用,例如这里v1
。 coalesce
支持整洁的点功能,因此我们使用!!!syms
。
df_sub <- df1 %>% left_join(df2, by='id') %>% select(v1.x, v1.y)
# . represents df_sub
nm <- gsub('.x','',names(df_sub)[1])
nms <- names(df_sub)
df_sub %>% mutate(!!sym(nm) := coalesce(!!!syms(nms)))
# A tibble: 6 x 3
v1.x v1.y v1
<dbl> <dbl> <dbl>
1 1 1 1
2 0 NA 0
3 NA 0 0
4 1 1 1
5 0 0 0
6 NA 1 1
sym
和syms
这些函数将字符串作为输入并将其转换为符号,然后我们使用!!
和!!!
取消引用。我们使用:=
是因为我们需要在mutate中使用字符串作为列名,请参见我的答案here。详细了解sym
,syms
,!!
和!!!
here
答案 2 :(得分:0)
这是另一种方式,类似于@utubun使用bind_rows
和summarise
的方法。
bind_rows(df1, df2) %>%
group_by(id) %>%
summarise_all(list(~mean(., na.rm = TRUE))) %>%
# convert NaN to NA (if required)
mutate_at(vars(-id), function(x) ifelse(is.nan(x), NA, x))