【问题标题】:Use `j` to select the join column of `x` and all its non-join columns使用 `j` 选择 `x` 的连接列及其所有非连接列
【发布时间】:2017-02-19 15:37:02
【问题描述】:

我有两个数据表:

library(data.table)
d1 <- data.table(grp = c("a", "c", "b", "a"), val = c(2, 3, 6, 7), y1 = 1:4, y2 = 5:8)

d2 <- data.table(grp = rep(c("a", "b", "c"), 2),
                 from = rep(c(1, 5), each = 3), to = rep(c(4, 10), each = 3), z = 11:16)

我执行非 equi 连接,其中 'd1' 中的值 'val' 应落在每个组 'grp' 的 'd2' 中的 'from' 和 'to' 定义的范围内。

d1[d2, on = .(grp, val >= from, val <= to), nomatch = 0]
#    grp val y1 y2 val.1  z
# 1:   a   1  1  5     4 11
# 2:   c   1  2  6     4 13
# 3:   a   5  4  8    10 14
# 4:   b   5  3  7    10 15

在输出中,连接变量来自i('val' 和 'val.1',在 'd2' 中的值分别为 'from' 和 'to')。但是,我希望有x 的加入列。现在,因为...

x 的列现在可以使用前缀 x. 来引用,并且在连接过程中特别有用,可以引用 x 的连接列,否则它们会被 i 屏蔽。

...这可以通过在j 中指定val = x.val 来实现:

d1[d2, .(grp, val = x.val, z), on = .(grp, val >= from, val <= to), nomatch = 0]

为了避免在j 中输入来自x 的所有非连接列(可能很多),我目前的解决方法是将上述内容与原始数据连接起来,从而得到所需的结果:

d1[d1[d2, .(grp, val = x.val, z), on = .(grp, val >= from, val <= to), nomatch = 0]
   , on = .(grp, val)]
#    grp val y1 y2  z
# 1:   a   2  1  5 11
# 2:   c   3  2  6 13
# 3:   a   7  4  8 14
# 4:   b   6  3  7 15

但是,这似乎有点笨拙。因此,我的问题是:如何一次性从x 中选择连接列以及jx 中的所有非连接列?


PS 我考虑过切换xi 数据集,以及on 中的条件。尽管这会产生所需的连接值,但它仍然需要后处理(删除、重命名和重新排序列)。

【问题讨论】:

  • 我不知道后处理仅限于您拥有的许多非 equi cols...看起来还不错,例如d2[d1, on=.(grp, from &lt;= val, to &gt;= val), nomatch=0][, `:=`(val = from, from = NULL, to = NULL)][]
  • 基于@docendo 的answer heremyabe 这个:idx &lt;- d2[d1, on = .(grp, from &lt;= val, to &gt;= val), which = TRUE]; d1[, z := d2$z[idx]][]?
  • 仅供参考,我在下面的答案中添加了@Jaap 评论的变体。

标签: r data.table


【解决方案1】:

PS 我考虑过切换 x 和 i 数据集,以及开启条件。尽管这会产生所需的连接值,但它仍然需要后处理(删除、重命名和重新排序列)。

后处理的数量受限于on= cols的数量:

d2[d1, on=.(grp, from <= val, to >= val), nomatch=0][, 
  `:=`(val = from, from = NULL, to = NULL)][]

看起来还不错。


根据@Jaap 的评论,这是另一种方式,通过更新连接将列添加到d1

nm2 = setdiff(names(d2), c("from","to","grp"))
d1[d2, on=.(grp, val >= from, val <= to), (nm2) := mget(sprintf("i.%s", nm2))]

这很有意义,因为所需的输出本质上是d1 加上来自d2 的一些列(因为d1 的每一行最多匹配d2 的一行)。

【讨论】:

    【解决方案2】:

    也许使用来自data.tablefoverlaps

    #create duplicate range
    setDT(d1)[,`:=`(val1 = val)]
    
    #setkey
    setkey(d1, grp, val, val1)
    setkey(d2, grp, from, to)
    
    #join
    d_merge <- foverlaps(d1, d2, nomatch = NA)
    setDT(d_merge)[,`:=`(from = NULL,
                         to = NULL,
                         val1 = NULL)]
    d_merge
    #    grp z val y1 y2
    #1:   a 11   2  1  5
    #2:   a 14   7  4  8
    #3:   b 15   6  3  7
    #4:   c 13   3  2  6
    

    【讨论】:

    • 感谢您的建议 (+1)!它确实给出了预期的结果。但是,我的问题的主要焦点是在此设置中使用 j。干杯。
    • @Henrik 谢谢。我同意!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    相关资源
    最近更新 更多