ims*_*msc 2 merge r data.table
我想更新旧的列data.table基于一个新的data.table,只有当值不NA.
DT_old = data.table(x=rep(c("a","b","c")), y=c(1,3,6), v=1:3, l=c(1,1,1))
DT_old
x y v l
1: a 1 1 1
2: b 3 2 1
3: c 6 3 1
DT_new = data.table(x=rep(c("b","c",'d')), y=c(9,6,10), v=c(2,NA,10), z=c(9,9,9))
DT_new
x y v z
1: b 9 2 9
2: c 6 NA 9
3: d 10 10 9
Run Code Online (Sandbox Code Playgroud)
我想要输出
x y v z
1: b 9 2 9
2: c 6 3 9
3: d 10 10 9
4: a 1 1 NA
Run Code Online (Sandbox Code Playgroud)
目前我正在合并这两个data.table并通过每个列并替换新data.table中的NA
DT_merged <- merge(DT_new, DT_old, all=TRUE, by='x')
DT_merged
x y.x v.x z y.y v.y l
1: a NA NA NA 1 1 1
2: b 9 2 9 3 2 1
3: c 6 NA 9 6 3 1
4: d 10 10 9 NA NA NA
DT_merged[is.na(y.x), y.x := y.y]
DT_merged[is.na(v.x), v.x := v.y]
DT_merged = DT_merged[, list(y=y.x, v=v.x, z=z)
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来做到这一点?
这是我如何处理这个问题.首先,我将DT_new根据x使用二进制连接的两个表的列的唯一值组合进行扩展
res <- setkey(DT_new, x)[unique(c(x, DT_old$x))]
res
# x y v z
# 1: b 9 2 9
# 2: c 6 NA 9
# 3: d 10 10 9
# 4: a NA NA NA
Run Code Online (Sandbox Code Playgroud)
然后,我将res使用另一个二进制连接通过引用更新两列
setkey(res, x)[DT_old, `:=`(y = i.y, v = i.v)]
res
# x y v z
# 1: a 1 1 NA
# 2: b 3 2 9
# 3: c 6 3 9
# 4: d 10 10 9
Run Code Online (Sandbox Code Playgroud)
在评论部分之后,您似乎正在尝试按照自己的条件加入每个列.在R或任何语言AFAIK中没有简单的方法来做这样的事情.因此,您自己的解决方案本身可能是一个不错的选择.
虽然,这里有一些其他选择,主要是从我不久前问过的类似问题中提取的
使用两个ifelse语句
setkey(res, x)[DT_old, `:=`(y = ifelse(is.na(y), i.y, y),
v = ifelse(is.na(v), i.v, v))]
Run Code Online (Sandbox Code Playgroud)
两个单独的条件连接
setkey(res, x) ; setkey(DT_old, x) ## old data set needs to be keyed too now
res[is.na(y), y := DT_old[.SD, y]]
res[is.na(v), v := DT_old[.SD, v]]
Run Code Online (Sandbox Code Playgroud)
两者都能满足您的需求.
PS
如果您不想要警告,则需要正确定义相应的列类,例如,v列in DT_new应定义为v= c(2L, NA_integer_, 10L)