昨天我给出了这样的答案:按五列匹配数据表以更改另一列中的值 https://stackoverflow.com/questions/39176643/matching-data-tables-by-five-columns-to-change-a-value-in-another-column/39176820#39176820.
在评论中,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);
这是我给出的解决方案not获取不匹配行的 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
我们需要的是为了id
值 12 及以下仍保留在dt1
替换为 NA (not因为他们的年龄为 12 岁及以下,并且not因为这些 id 值缺失了dt2
,但是因为加入key
列,即V1
and V2
,不会导致这些行的匹配dt1
反对dt2
).
正如我在该问题的评论中所说,解决方法是预先分配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
我认为解决方法是好的,但我不确定为什么 data.table 似乎无法通过索引连接分配操作一次性实现此功能。以下是我探索的三个死胡同:
1: nomatch
data.table 提供了nomatch
论点看起来有点像all
, all.x
, and all.y
的论据merge()
。这实际上是一个非常有限的论点;它只允许从右连接更改(nomatch=NA
,默认值)到内连接(nomatch=0
)。我们无法用它实现左连接。
2: flip dt1
and dt2
Since dt1[dt2]
是右连接,我们可以翻转它,意思是dt2[dt1]
,实现相应的左连接。
这也不起作用,因为我们需要使用:=
中的就地赋值语法j
要分配给的参数dt1
,在翻转调用下,我们将分配给dt2
。我尝试分配给i.id
在翻转命令下,但不影响原来的dt1
.
3: use merge.data.table()
我们可以打电话merge.data.table()
与all.x=T
实现左连接的参数。现在的问题是merge.data.table()
has no j
参数,并且它根本不提供就地分配左(或右)表的列的方法。
那么,是否可以使用 data.table 来执行此操作?如果是这样,最好的方法是什么?