是否可以使用data.table index-join-assignment惯用法进行左连接并在i的非匹配行中分配NA到x?

bgo*_*dst 7 r left-join assign data.table

昨天我给出了这个答案:将数据表匹配五列以更改另一列中的值.

在评论中,OP询问我们是否能够有效地实现两个表的左连接,从而获得将导致右表分配给左表的NA.在我看来,data.table并没有提供任何这样做的方法.

以下是我在该问题中使用的示例案例:

set.seed(1L);
dt1 <- data.table(id=1:12,expand.grid(V1=1:3,V2=1:4),blah1=rnorm(12L));
dt2 <- data.table(id=13:18,expand.grid(V1=1:2,V2=1:3),blah2=rnorm(6L));
dt1;
##     id V1 V2      blah1
##  1:  1  1  1 -0.6264538
##  2:  2  2  1  0.1836433
##  3:  3  3  1 -0.8356286
##  4:  4  1  2  1.5952808
##  5:  5  2  2  0.3295078
##  6:  6  3  2 -0.8204684
##  7:  7  1  3  0.4874291
##  8:  8  2  3  0.7383247
##  9:  9  3  3  0.5757814
## 10: 10  1  4 -0.3053884
## 11: 11  2  4  1.5117812
## 12: 12  3  4  0.3898432
dt2;
##    id V1 V2       blah2
## 1: 13  1  1 -0.62124058
## 2: 14  2  1 -2.21469989
## 3: 15  1  2  1.12493092
## 4: 16  2  2 -0.04493361
## 5: 17  1  3 -0.01619026
## 6: 18  2  3  0.94383621
key <- paste0('V',1:2);
Run Code Online (Sandbox Code Playgroud)

这是我给出的解决方案,它不会获得非匹配行的NA:

dt1[dt2,on=key,id:=i.id];
dt1;
##     id V1 V2      blah1
##  1: 13  1  1 -0.6264538
##  2: 14  2  1  0.1836433
##  3:  3  3  1 -0.8356286
##  4: 15  1  2  1.5952808
##  5: 16  2  2  0.3295078
##  6:  6  3  2 -0.8204684
##  7: 17  1  3  0.4874291
##  8: 18  2  3  0.7383247
##  9:  9  3  3  0.5757814
## 10: 10  1  4 -0.3053884
## 11: 11  2  4  1.5117812
## 12: 12  3  4  0.3898432
Run Code Online (Sandbox Code Playgroud)

我们需要的是对id值12和下留在dt1与NAS(更换不是因为他们是12岁以下,而不是因为这些ID值从丢失dt2,但由于加入的key列,即V1V2,不导致在比赛中那些行dt1dt2).

正如我在该问题的评论中所说,解决方法是预先分配dt1$id给所有NA,然后运行索引连接分配.因此,这是预期的输出:

dt1$id <- NA;
dt1[dt2,on=key,id:=i.id];
dt1;
##     id V1 V2      blah1
##  1: 13  1  1 -0.6264538
##  2: 14  2  1  0.1836433
##  3: NA  3  1 -0.8356286
##  4: 15  1  2  1.5952808
##  5: 16  2  2  0.3295078
##  6: NA  3  2 -0.8204684
##  7: 17  1  3  0.4874291
##  8: 18  2  3  0.7383247
##  9: NA  3  3  0.5757814
## 10: NA  1  4 -0.3053884
## 11: NA  2  4  1.5117812
## 12: NA  3  4  0.3898432
Run Code Online (Sandbox Code Playgroud)

我认为解决方法是可以的,但我不确定为什么data.table似乎无法通过索引连接分配操作一次性完成此功能.以下是我探讨的三个死胡同:

1: nomatch

data.table提供了一个nomatch参数,它看起来有点像了all,all.xall.y论据merge().这实际上是一个非常有限的论点; 它只允许从右连接(nomatch=NA默认)更改为内连接(nomatch=0).我们无法实现左连接.

2:翻转dt1dt2

由于dt1[dt2]是一个正确的连接,我们可以翻转它,意思是dt2[dt1],实现相应的左连接.

这不会起作用,因为我们需要在参数中使用:=就地赋值语法j来分配dt1,而在翻转调用下,我们将改为分配dt2.我尝试i.id在翻转命令下分配,但它没有影响原始dt1.

3:使用merge.data.table()

我们可以merge.data.table()使用all.x=T参数调用来实现左连接.现在的问题是merge.data.table()没有j参数,它根本没有提供就地分配左(或右)表的列的方法.


那么,是否可以使用data.table执行此操作?如果是这样,最好的方法是什么?

jan*_*cki 8

AFAIU你只是想查找id从列dt2dt1.当您加入时,原始id变量dt1似乎与整个过程无关V1,V2,您不希望dt1$id在结果中包含值.因此,技术上正确的解决方法是根本不使用该列.

set.seed(1)
library(data.table)
dt1 <- data.table(id=1:12,expand.grid(V1=1:3,V2=1:4),blah1=rnorm(12L));
dt2 <- data.table(id=13:18,expand.grid(V1=1:2,V2=1:3),blah2=rnorm(6L));
on = paste0("V",1:2) # I rename to `on` to not mask `key` function
dt1[,id:=NULL
    ][dt2,on=on,id:=i.id
      ][]
#  V1 V2      blah1 id
# 1:  1  1 -0.6264538 13
# 2:  2  1  0.1836433 14
# 3:  3  1 -0.8356286 NA
# 4:  1  2  1.5952808 15
# 5:  2  2  0.3295078 16
# 6:  3  2 -0.8204684 NA
# 7:  1  3  0.4874291 17
# 8:  2  3  0.7383247 18
# 9:  3  3  0.5757814 NA
#10:  1  4 -0.3053884 NA
#11:  2  4  1.5117812 NA
#12:  3  4  0.3898432 NA
Run Code Online (Sandbox Code Playgroud)

除了问题...
- ;如果只有单个表达式要评估
,则dt1[, id := NA_integer_]不必在行尾使用 - 使用而不是dt1$id <- NA
- set.seed在提供代码rnorm和其他随机性相关调用时使用