首页 > 解决方案 > 意外行为非等连接data.table R

问题描述

考虑一些样本数据

library(data.table)
dt1 <- data.table(foo = 1:4, bar = letters[1:4])
dt2 <- data.table(foo1 = 2:5, bar1 = LETTERS[1:4])

我正在尝试通过非等连接加入这两个示例 data.tables(这也需要我设置笛卡尔连接选项):

options("datatable.allow.cartesian" = T)
dt3 <- dt1[dt2, on = .(foo < foo1), nomatch = 0L]

dt3结果是:

    foo bar bar1
 1:   2   a    A
 2:   3   a    B
 3:   3   b    B
 4:   4   a    C
 5:   4   b    C
 6:   4   c    C
 7:   5   a    D
 8:   5   b    D
 9:   5   c    D
10:   5   d    D

但是,这样做有两个问题:

  1. foo没有值 5(这是一个明显的错误)
  2. foo1不存在于输出中(这可能会限制进一步的条件;如果有的话)

为了绕过第二个条件,我尝试了:

dt2[, foo11 := foo1]
dt4 <- dt1[dt2, on = .(foo < foo1), nomatch = 0L]
options("datatable.allow.cartesian" = F)

这给了我dt4

    foo bar bar1 foo11
 1:   2   a    A     2
 2:   3   a    B     3
 3:   3   b    B     3
 4:   4   a    C     4
 5:   4   b    C     4
 6:   4   c    C     4
 7:   5   a    D     5
 8:   5   b    D     5
 9:   5   c    D     5
10:   5   d    D     5

所以这里foo11本质上是一个错误列的副本,foo它看起来像另一个由于非 equi 连接而导致的错误。

我在这里错过任何一点或做错了吗?

标签: rdata.table

解决方案


我认为这种行为是预期的,除了变量的命名非常令人惊讶。我对您的示例数据进行了一些调整,以表明一切正常:

dt1 <- data.table(foo = 1:4, bar = letters[1:4])
dt2 <- data.table(foo1 = 2:4, bar1 = letters[2:4]) # small change here

dt1[dt2, on = .(foo < foo1), allow.cartesian = TRUE][dt1, on = "bar"]
    foo bar bar1 i.foo
 1:   2   a    b     1
 2:   3   a    c     1
 3:   4   a    d     1
 4:   5   a    e     1
 5:   3   b    c     2
 6:   4   b    d     2
 7:   5   b    e     2
 8:   4   c    d     3
 9:   5   c    e     3
10:   5   d    e     4

对我来说,行为是预期的,只是第一列被命名foo而不是foo1. 这就是为什么您将fool1其视为“错误 foo : it's actually a copy offoo1” 的错误副本。

编辑:一种可能的解决方法:

这不是很优雅,但是一种解决方法:

dt1[dt2, .(foo = x.foo, foo1, bar, bar1), on = .(foo < foo1), allow.cartesian = TRUE]
    foo foo1 bar bar1
 1:   1    2   a    b
 2:   1    3   a    c
 3:   2    3   b    c
 4:   1    4   a    d
 5:   2    4   b    d
 6:   3    4   c    d
 7:   1    5   a    e
 8:   2    5   b    e
 9:   3    5   c    e
10:   4    5   d    e

x.foo保留原来的,真实的foofoo1仍然是它的样子,所以你可以返回两个变量。


推荐阅读