【问题标题】:Odd behavior when joining with multiple conditions加入多个条件时的奇怪行为
【发布时间】:2015-11-09 03:15:40
【问题描述】:

answering this question 中关于使用data.table 包进行滚动连接时,我在使用多个条件时遇到了一些奇怪的行为。

考虑以下数据集:

dt <- data.table(t_id = c(1,4,2,3,5), place = c("a","a","d","a","d"), num = c(5.1, 5.1, 6.2, 5.1, 6.2), key=c("place"))
dt_lu <- data.table(f_id = c(rep(1,4),rep(2,3)), place = c("a","b","c","d","a","d","a"), num = c(6,7,8,9,6,7,8), key=c("place"))

当我想将dtdt_lu 一起加入时,只有dt_lu 具有相同place 并且dt_lu$num 高于dt$num 的情况如下:

dt_lu[dt, list(tid = i.t_id,
               tnum = i.num,
               fnum = num[i.num < num],
               fid = f_id),
      by = .EACHI]

我得到了想要的结果:

    place tid tnum fnum fid
 1:     a   1  5.1    6   1
 2:     a   1  5.1    6   2
 3:     a   1  5.1    8   2
 4:     a   4  5.1    6   1
 5:     a   4  5.1    6   2
 6:     a   4  5.1    8   2
 7:     a   3  5.1    6   1
 8:     a   3  5.1    6   2
 9:     a   3  5.1    8   2
10:     d   2  6.2    9   1
11:     d   2  6.2    7   2
12:     d   5  6.2    9   1
13:     d   5  6.2    7   2

当我想添加附加条件时,可以通过如下链接附加条件轻松获得所需结果:

dt_lu[dt, list(tid = i.t_id,
               tnum = i.num,
               fnum = num[i.num < num],
               fid = f_id),
      by = .EACHI][fnum - tnum < 2]

这给了我:

   place tid tnum fnum fid
1:     a   1  5.1    6   1
2:     a   1  5.1    6   2
3:     a   4  5.1    6   1
4:     a   4  5.1    6   2
5:     a   3  5.1    6   1
6:     a   3  5.1    6   2
7:     d   2  6.2    7   2
8:     d   5  6.2    7   2

但是,当我添加额外条件时(即:差异必须小于2)如下:

dt_lu[dt, list(tid = i.t_id,
               tnum = i.num,
               fnum = num[i.num < num & num - i.num < 2],
               fid = f_id),
      by = .EACHI]

我没有得到预期的结果:

    place tid tnum fnum fid
 1:     a   1  5.1    6   1
 2:     a   1  5.1    6   2
 3:     a   1  5.1    6   2
 4:     a   4  5.1    6   1
 5:     a   4  5.1    6   2
 6:     a   4  5.1    6   2
 7:     a   3  5.1    6   1
 8:     a   3  5.1    6   2
 9:     a   3  5.1    6   2
10:     d   2  6.2    7   1
11:     d   2  6.2    7   2
12:     d   5  6.2    7   1
13:     d   5  6.2    7   2

此外,我收到以下警告消息:

警告信息:在[.data.table(dt_lu, dt, list(tid = i.t_id, tnum = i.num, fnum = num[i.num

预期的结果是:

    place tid tnum fnum fid
 1:     a   1  5.1    6   1
 2:     a   1  5.1    6   2
 4:     a   4  5.1    6   1
 5:     a   4  5.1    6   2
 7:     a   3  5.1    6   1
 8:     a   3  5.1    6   2
11:     d   2  6.2    7   2
13:     d   5  6.2    7   2

我特意保留了第一个示例中的行号,以显示最终结果中必须维护哪些行(这与工作解决方案相同)。

正如this answer 所示,应该可以在连接操作中使用多个条件。

我尝试了以下替代方法,但它们都不起作用:

dt_lu[dt, list(tid = i.t_id,
               tnum = i.num,
               fnum = num[(i.num < num) & (num - i.num < 2)],
               fid = f_id),
      by = .EACHI]

dt_lu[dt, {
  val = num[(i.num < num) & (num - i.num < 2)];
  list(tid = i.t_id,
       tnum = i.num,
       fnum = val,
       fid = f_id)},
  by = .EACHI]

有人能解释一下为什么我在连接操作中没有得到想要的结果吗?

【问题讨论】:

    标签: r join data.table


    【解决方案1】:

    警告消息泄露了问题。此外,在这里使用print() 很有帮助。

    dt_lu[dt, print(i.num < num & num - i.num < 2), by=.EACHI]
    # [1]  TRUE  TRUE FALSE
    # [1]  TRUE  TRUE FALSE
    # [1]  TRUE  TRUE FALSE
    # [1] FALSE  TRUE
    # [1] FALSE  TRUE
    # Empty data.table (0 rows) of 3 cols: place,place,num
    

    考虑条件评估为TRUE, TRUE, FALSE 的第一种情况。该组有 3 个观察值。而您的j-expression 包含:

    .(tid = i.t_id,
      tnum = i.num,
      fnum = num[i.num < num & num - i.num < 2],
      fid = f_id)
    

    i.t_idi.num 的长度为 1(因为它们来自 dt)。但是num[..condn..] 将返回长度 = 2,而f_id 将返回长度 = 3。长度 = 1 和长度 = 2 的项目将被回收到最长的项目/向量 = 3 的长度。这会导致不正确的结果.由于 3 不能完全被 2 整除,因此它会返回警告。

    你打算做的是:

    .(tid = i.t_id,
      tnum = i.num,
      fnum = num[i.num < num & num - i.num < 2],
      fid = f_id[i.num < num & num - i.num < 2])
    

    或等效:

    {  
      idx = i.num < num & num - i.num < 2
      .(tid  = i.t_id, tnum = i.num, fnum = num[idx], fid  = f_id[idx])
    }
    

    把它放在一起:

    dt_lu[dt, 
           {
             idx = i.num < num & num - i.num < 2
            .(tid  = i.t_id, tnum = i.num, fnum = num[idx], fid  = f_id[idx])
           }, 
    by = .EACHI]
    #    place tid tnum fnum fid
    # 1:     a   1  5.1    6   1
    # 2:     a   1  5.1    6   2
    # 3:     a   4  5.1    6   1
    # 4:     a   4  5.1    6   2
    # 5:     a   3  5.1    6   1
    # 6:     a   3  5.1    6   2
    # 7:     d   2  6.2    7   2
    # 8:     d   5  6.2    7   2
    

    【讨论】:

    • 谢谢!如果能很好地解释您的回答,我很幸运只使用一个条件,因为fnumfid 的观察次数相同。
    猜你喜欢
    • 2021-07-13
    • 2016-12-15
    • 2014-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-27
    • 2015-02-01
    • 1970-01-01
    相关资源
    最近更新 更多