R左外连接0填充而不是NA,同时保留左表中的有效NA

Mek*_*lay 15 merge r left-join dplyr data.table

在两个数据表(dt1,dt2)上进行左外连接的最简单方法是使用填充值为0(或其他某个值)而不是NA(默认值)而不覆盖左数据表中的有效NA值?

一个常见的答案,例如在这个线程中,使用dplyr::left_join或者data.table::merge或者用data.tabledt2 [dt1]键控列括号语法进行左外连接,接着是第二步,简单地用连接数据表替换所有NA0.例如:

library(data.table);
dt1 <- data.table(x=c('a', 'b', 'c', 'd', 'e'), y=c(NA, 'w', NA, 'y', 'z'));
dt2 <- data.table(x=c('a', 'b', 'c'), new_col=c(1,2,3));
setkey(dt1, x);
setkey(dt2, x);
merged_tables <- dt2[dt1];
merged_tables[is.na(merged_tables)] <- 0;
Run Code Online (Sandbox Code Playgroud)

这种方法必然假定没有有效的NA值dt1需要保留.然而,正如您在上面的示例中所看到的,结果是:

   x new_col y
1: a       1 0
2: b       2 w
3: c       3 0
4: d       0 y
5: e       0 z
Run Code Online (Sandbox Code Playgroud)

但是期望的结果是:

   x new_col y
1: a       1 NA
2: b       2 w
3: c       3 NA
4: d       0 y
5: e       0 z
Run Code Online (Sandbox Code Playgroud)

在这种微不足道的情况下,不是使用data.table所有元素替换上面的语法,只new_col需要替换NA值:

library(dplyr);
merged_tables <- mutate(merged_tables, new_col = ifelse(is.na(new_col), 0, new_col));
Run Code Online (Sandbox Code Playgroud)

但是,这种方法对于合并了数十个或数百个新列的非常大的数据集是不实用的,有时会使用动态创建的列名.即使列名称都是提前知道的,列出所有新列并在每个列上进行mutate-style替换也是非常难看的.

肯定有更好的办法?如果任何,或者括号的语法容易让用户指定除NA之外的值dplyr::left_join,则可以简单地解决该问题.就像是:data.table::mergedata.tablefill

merged_tables <- data.table::merge(dt1, dt2, by="x", all.x=TRUE, fill=0);
Run Code Online (Sandbox Code Playgroud)

data.tabledcast功能允许用户指定fill值,所以我认为必须有一个更简单的方法来做到这一点,我只是没想到.

建议?

编辑:@jangorecki在评论中指出,当前在data.tableGitHug页面上打开了一个功能请求,完全按照我刚才提到的那样更新nomatch=0语法.应该在下一个版本中data.table.

小智 5

我偶然发现了与dplyr相同的问题,并编写了一个小的函数来解决我的问题。(该解决方案需要tidyr和dplyr)

left_join0 <- function(x, y, fill = 0L){
  z <- left_join(x, y)
  tmp <- setdiff(names(z), names(x))
  z <- replace_na(z, setNames(as.list(rep(fill, length(tmp))), tmp))
  z
}
Run Code Online (Sandbox Code Playgroud)


Sam*_*rke 2

您能否使用列索引仅引用新列,因为left_join它们都位于结果 data.frame 的右侧?这里它是 dplyr 中的:

dt1 <- data.frame(x = c('a', 'b', 'c', 'd', 'e'),
                  y = c(NA, 'w', NA, 'y', 'z'),
                  stringsAsFactors = FALSE)
dt2 <- data.frame(x = c('a', 'b', 'c'),
                  new_col = c(1,2,3),
                  stringsAsFactors = FALSE)

merged <- left_join(dt1, dt2)
index_new_col <- (ncol(dt1) + 1):ncol(merged)
merged[, index_new_col][is.na(merged[, index_new_col])] <- 0

> merged
  x    y new_col
1 a <NA>       1
2 b    w       2
3 c <NA>       3
4 d    y       0
5 e    z       0
Run Code Online (Sandbox Code Playgroud)