我确定我忽略了显而易见的内容,但是我找不到一种方法可以一步一步地将data.table非查找联接中的“ lookup”表的所有列联接在一起。
我看了Arun的演示文稿(https://github.com/Rdatatable/data.table/wiki/talks/ArunSrinivasanSatRdaysBudapest2016.pdf)和多个SO问题,但几乎所有问题都只涉及更新单个列,而不涉及多个列。
假设我有2个data.tables a和b:
library(data.table)
a <- data.table(Company_ID = c(1,1,1,1),
salary = c(2000, 3000, 4000, 5000))
# Company_ID salary
# 1: 1 2000
# 2: 1 3000
# 3: 1 4000
# 4: 1 5000
b <- data.table(cat = c(1,2),
LB = c(0, 3000),
UB = c(3000,5000),
rep = c("Bob","Alice"))
# cat LB UB rep
# 1: 1 0 3000 Bob
# 2: 2 3000 5000 Alice
Run Code Online (Sandbox Code Playgroud)
我最终想要的是将cat,LB,UB,rep(在中的所有cols b)与表进行匹配a:
# Company_ID salary cat LB UB rep
# 1: 1 2000 1 0 3000 Bob
# 2: 1 3000 2 3000 5000 Alice
# 3: 1 4000 2 3000 5000 Alice
Run Code Online (Sandbox Code Playgroud)
当前,我设法做到这一点的唯一方法是使用以下两行:
a <- a[b, on = .(salary >= LB, salary < UB), cat := cat]
a[b, on = .(cat == cat)]
Run Code Online (Sandbox Code Playgroud)
它输出所需的表,但看起来很麻烦,根本不像一种data.table方法。任何帮助将不胜感激!
由于您希望每一行都有结果a,因此您应该像这样进行联接b[a, ...]:
b[a, on=.(LB <= salary, UB > salary), nomatch=0,
.(Company_ID, salary, cat, LB = x.LB, UB = x.UB, rep)]
Company_ID salary cat LB UB rep
1: 1 2000 1 0 3000 Bob
2: 1 3000 2 3000 5000 Alice
3: 1 4000 2 3000 5000 Alice
Run Code Online (Sandbox Code Playgroud)
nomatch=0表示我们将删除a中不匹配的行b。UB和LB列。bx.*?data.tablex[i]关于奇怪的默认cols,有一个开放的问题可以更改该行为:#1615。
(现在已修复以下的第1989年版本,请参见Uwe的答案。)
或者...一种可行的方法,可以避免显式列出所有列:将a的列添加到b,然后添加子集b:
b[a, on=.(LB <= salary, UB > salary), names(a) := mget(paste0("i.", names(a)))]
b[b[a, on=.(LB <= salary, UB > salary), which=TRUE, nomatch=0]]
Run Code Online (Sandbox Code Playgroud)
这有两个问题。首先,有一个错误会导致非等额联接在遇到mget(#1989)时中断。临时的解决方法是枚举a的列:
b[a, on=.(LB <= salary, UB > salary), `:=`(Company_ID = i.Company_ID, salary = i.salary)]
b[b[a, on=.(LB <= salary, UB > salary), which=TRUE, nomatch=0]]
Run Code Online (Sandbox Code Playgroud)
其次,两次执行此联接效率不高(一次为:=,第二次为which),但是我看不到任何解决方法……也许证明允许同时允许j和which?