非equi连接在一个步骤中在data.table中添加范围表的所有列

时间:2017-01-13 15:13:43

标签: r join data.table

我确定我忽视了显而易见的事情,但我无法找到一种方法来加入"查找"的所有列。只需一步即可data.table非等同加入的表

我查看了Arun的演示文稿(https://github.com/Rdatatable/data.table/wiki/talks/ArunSrinivasanSatRdaysBudapest2016.pdf)和多个SO问题,但几乎所有问题都只涉及更新单个列,而不是加入多个列。

假设我有2个data.tables ab

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

我最终想要的是匹配cat,LB,UB,rep(b中的所有cols)到表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

目前,我设法做到的唯一方法是使用以下两行:

a <- a[b, on = .(salary >= LB, salary < UB), cat := cat]
a[b, on = .(cat == cat)]

哪个输出所需的表,但看起来很麻烦,完全不像data.table方法。任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:2)

由于您希望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
  • nomatch=0表示我们会删除a中无法匹配的b行。
  • 我们需要使用UB前缀明确引用LB中的bx.*列(来自?data.table文档,其中参数命名为x[i])。

关于奇怪的默认cols,有一个未解决的问题可以改变这种行为:#1615

替代...... 应采用的一种方法,避免明确列出所有列:将a的列添加到b,然后将子集{{1 }}:

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]] #1989)时,会出现导致非等联接中断的错误。临时解决方法是枚举mget列:

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]] ,另一次为:=),但我无法解决这个问题。 。也许可以证明功能请求允许whichj

答案 1 :(得分:2)

现在,#1989已使用data.table版本1.12.3(正在开发中)修复,可以从ab中选择所有列,而无需说明每个列的名称明确地:

a[b, on = .(salary >= LB, salary < UB), 
  mget(c(paste0("x.", names(a)), paste0("i.", names(b))))]
   x.Company_ID x.salary i.cat i.LB i.UB i.rep
1:            1     2000     1    0 3000   Bob
2:            1     3000     2 3000 5000 Alice
3:            1     4000     2 3000 5000 Alice

返回OP的预期结果,但列标题除外。

要更改列标题,可以使用setnames()包中的data.table

result <- a[b, on = .(salary >= LB, salary < UB), 
            mget(c(paste0("x.", names(a)), paste0("i.", names(b))))] 
setnames(result, c(names(a), names(b)))
result
   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

或者,通过配管并使用set_names()包中的magrittr

library(magrittr)
a[b, on = .(salary >= LB, salary < UB), 
  mget(c(paste0("x.", names(a)), paste0("i.", names(b)))) %>% 
    set_names(c(names(a), names(b)))]
   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

诚然,这仍然很麻烦。