在R中合并两个df替换缺失值

时间:2019-05-21 16:05:45

标签: r merge

我想匹配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的各种联接,但是不知何故,我无法理解。

3 个答案:

答案 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

这里有一个简单的示例,说明symsyms对每个包含.x和.y列的变量的作用,例如这里v1coalesce支持整洁的点功能,因此我们使用!!!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

symsyms这些函数将字符串作为输入并将其转换为符号,然后我们使用!!!!!取消引用。我们使用:=是因为我们需要在mutate中使用字符串作为列名,请参见我的答案here。详细了解symsyms!!!!! here

答案 2 :(得分:0)

这是另一种方式,类似于@utubun使用bind_rowssummarise的方法。

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))