【问题标题】:Merge R data frame or data table and overwrite values of multiple columns合并R数据框或数据表并覆盖多列的值
【发布时间】:2019-03-24 08:55:13
【问题描述】:

如何合并R 中的两个数据表(或数据框),并保留每个匹配列中的非NA 值?如果明确指定每个单独的列(至少据我所知),问题Merge data frames and overwrite values 提供了一个解决方案。但是,我在两个数据表之间有 40 多个公共列,并且两者中的哪一个具有 NA 与有效值有点随机。因此,为 40 列编写 ifelse 语句似乎效率低下。

下面是一个简单的例子,我想通过iddate 列加入(merge)两个data.tables:

dt_1 <- data.table::data.table(id = "abc",
                               date = "2018-01-01",
                               a = 3, 
                               b = NA_real_,
                               c = 4, 
                               d = 6,
                               e = NA_real_)
setkey(dt_1, id, date)

> dt_1
    id       date a  b c d  e
1: abc 2018-01-01 3 NA 4 6 NA

dt_2 <- data.table::data.table(id = "abc", 
                               date = "2018-01-01",
                               a = 3, 
                               b = 5,
                               c = NA_real_, 
                               d = 6,
                               e = NA_real_)
setkey(dt_2, id, date)
> dt_2
    id       date a b  c d  e
1: abc 2018-01-01 3 5 NA 6 NA

这是我想要的输出:

> dt_out
    id       date a b c d  e
1: abc 2018-01-01 3 5 4 6 NA

我也尝试了left_join two data frames and overwritedplyr::anti_join 解决方案,但没有成功。

【问题讨论】:

  • 如果同一变量的非 NA 值具有相同的 id 会发生什么?你愿意把那个从你的“左边”桌子上拿下来吗?
  • @Hamed 好问题。我正在考虑这个问题,但不想让事情变得过于复杂。是的,假设我们保留了左表的值。谢谢!

标签: r dplyr data.table


【解决方案1】:

您可以使用dplyr::coalesce 来做到这一点,它将返回向量中的第一个非缺失值。

(编辑:您也可以直接在数据框上使用dplyr::coalesce,无需在下面创建函数。为了完整起见,将其留在那里,作为原始答案的记录。)

归功于应得的:这段代码主要来自this blog post,它构建了一个函数,该函数将获取两个数据框并执行您需要的操作(如果存在,则从x数据框获取值)。

coalesce_join <- function(x, 
                          y, 
                          by, 
                          suffix = c(".x", ".y"), 
                          join = dplyr::full_join, ...) {
    joined <- join(x, y, by = by, suffix = suffix, ...)
    # names of desired output
    cols <- union(names(x), names(y))

    to_coalesce <- names(joined)[!names(joined) %in% cols]
    suffix_used <- suffix[ifelse(endsWith(to_coalesce, suffix[1]), 1, 2)]
    # remove suffixes and deduplicate
    to_coalesce <- unique(substr(
        to_coalesce, 
        1, 
        nchar(to_coalesce) - nchar(suffix_used)
    ))

    coalesced <- purrr::map_dfc(to_coalesce, ~dplyr::coalesce(
        joined[[paste0(.x, suffix[1])]], 
        joined[[paste0(.x, suffix[2])]]
    ))
    names(coalesced) <- to_coalesce

    dplyr::bind_cols(joined, coalesced)[cols]
}

【讨论】:

  • dplyr::coalesce(dt_1, dt_2)?
  • 正如@Frank 所暗示的,我没有看到仅使用dplyr::coalesce 的结果有实际差异。我错过了什么吗?尽管如此,coalesce 是一个我以前不知道的有用功能,所以谢谢!
【解决方案2】:

我可能会将数据放在长格式中并放弃欺骗:

k = key(dt_1)
DTList = list(dt_1, dt_2)

DTLong = rbindlist(lapply(DTList, function(x) melt(x, id=k)))    
setorder(DTLong, na.last = TRUE)    
unique(DTLong, by=c(k, "variable"))

    id       date variable value
1: abc 2018-01-01        a     3
2: abc 2018-01-01        b     5
3: abc 2018-01-01        c     4
4: abc 2018-01-01        d     6
5: abc 2018-01-01        e    NA

【讨论】:

    【解决方案3】:

    我们可以使用我的包safejoin,进行左连接并使用dplyr::coalesce处理冲突

    # devtools::install_github("moodymudskipper/safejoin")
    library(safejoin)
    
    safe_left_join(dt_1, dt_2, by = "id", conflict = coalesce)
    #    id       date a b c d  e
    # 1 abc 2018-01-01 3 5 4 6 NA
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-09
      • 1970-01-01
      • 2016-06-25
      • 2016-07-09
      • 2018-01-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多