是否可以使用 data.table index-join-assignment idiom 进行左连接并在 i 到 x 的非匹配行中分配 NA?
Is it possible to use the data.table index-join-assignment idiom to do a left join and assign NAs in the non-matching rows of i to x?
昨天我给出了这个答案:。
在评论中,OP 询问我们是否可以有效地实现两个 table 的左连接,从而获得将导致正确的 table 分配给左 table。在我看来 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 获取不匹配行的 NAs:
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( 而不是 ,因为它们是 12 并且下,并且 不是 因为 dt2
中缺少这些 id 值,而是因为 key
列上的连接,即 V1
和 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
参数,它看起来有点像 merge()
的 all
、all.x
和 all.y
参数.这实际上是一个非常有限的论点;它只允许从右连接(nomatch=NA
,默认值)更改为内部连接(nomatch=0
)。我们不能用它实现左连接。
2: 翻转 dt1
和 dt2
由于dt1[dt2]
是右连接,我们可以将其翻转,即dt2[dt1]
,实现对应的左连接
这也行不通,因为我们需要在 j
参数中使用 :=
就地赋值语法来赋值给 dt1
,并且在翻转调用下,我们将改为分配给 dt2
。我尝试在 flipped 命令下分配给 i.id
,但它并没有影响原来的 dt1
.
3: 使用 merge.data.table()
我们可以用all.x=T
参数调用merge.data.table()
来实现左连接。现在的问题是 merge.data.table()
没有 j
参数,它根本没有提供就地分配左(或右)列的方法 table.
那么,是否可以使用 data.table 执行此操作?如果是这样,最好的方法是什么?
AFAIU 您只想查找从 dt2
到 dt1
的 id
列。 dt1
中的原始 id
变量似乎与整个过程无关,因为您加入 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
除了问题...
- 如果只有一个表达式要计算
,则不必在行尾使用 ;
- 使用 dt1[, id := NA_integer_]
而不是 dt1$id <- NA
- 在为 rnorm
和其他随机相关调用
提供代码时使用 set.seed
昨天我给出了这个答案:
在评论中,OP 询问我们是否可以有效地实现两个 table 的左连接,从而获得将导致正确的 table 分配给左 table。在我看来 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 获取不匹配行的 NAs:
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( 而不是 ,因为它们是 12 并且下,并且 不是 因为 dt2
中缺少这些 id 值,而是因为 key
列上的连接,即 V1
和 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
参数,它看起来有点像 merge()
的 all
、all.x
和 all.y
参数.这实际上是一个非常有限的论点;它只允许从右连接(nomatch=NA
,默认值)更改为内部连接(nomatch=0
)。我们不能用它实现左连接。
2: 翻转 dt1
和 dt2
由于dt1[dt2]
是右连接,我们可以将其翻转,即dt2[dt1]
,实现对应的左连接
这也行不通,因为我们需要在 j
参数中使用 :=
就地赋值语法来赋值给 dt1
,并且在翻转调用下,我们将改为分配给 dt2
。我尝试在 flipped 命令下分配给 i.id
,但它并没有影响原来的 dt1
.
3: 使用 merge.data.table()
我们可以用all.x=T
参数调用merge.data.table()
来实现左连接。现在的问题是 merge.data.table()
没有 j
参数,它根本没有提供就地分配左(或右)列的方法 table.
那么,是否可以使用 data.table 执行此操作?如果是这样,最好的方法是什么?
AFAIU 您只想查找从 dt2
到 dt1
的 id
列。 dt1
中的原始 id
变量似乎与整个过程无关,因为您加入 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
除了问题...
- 如果只有一个表达式要计算
,则不必在行尾使用 ;
- 使用 dt1[, id := NA_integer_]
而不是 dt1$id <- NA
- 在为 rnorm
和其他随机相关调用
set.seed