【问题标题】:R Data.Table Join on ConditionalsR Data.Table 条件连接
【发布时间】:2015-04-29 03:50:42
【问题描述】:

我有两个表,我想以与以下 SQL 相同的方式将它们连接在一起,其中我在多个条件下连接,而不仅仅是相等。

require(sqldf)
require(data.table)

dt <- data.table(num=c(1, 2, 3, 4, 5, 6), 
char=c('A', 'A', 'A', 'B', 'B', 'B'), 
bool=c(TRUE, FALSE, TRUE, FALSE, TRUE, FALSE))

dt_two <- data.table(
num =c(6, 1, 5, 2, 4, 3), 
char=c('A', 'A', 'A', 'B', 'B', 'B'), 
bool=c(TRUE, FALSE, TRUE, FALSE, TRUE, FALSE))


dt_out_sql <- sqldf('
    select dtone.num, dtone.char, dtone.bool, SUM(dttwo.num) as SUM,  
   MIN(dttwo.num) as MIN
    from dt as dtone INNER join dt_two as dttwo on 
    (dtone.char = dttwo.char) and 
    (dtone.num >= dttwo.num OR dtone.bool)
GROUP BY dtone.num, dtone.char, dtone.bool')

出于性能和灵活性的原因,我想避免使用 SQL 解决方案。进行交叉连接,然后进行过滤/聚合也是如此——它会创建一个中间表,其中包含许多不必要的记录供我过滤掉。

非常感谢!

更新——我最初的例子是匆忙完成的。在我的实际问题中,我没有进行自我加入。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    这是一种方法:

    require(data.table)
    setkey(dt, char)
    setkey(dt_two, char)
    
    dt_two[dt, {
       val = num[i.bool | i.num >= num]; 
       list(num=i.num, bool=i.bool, sum=sum(val), min=min(val))
    }, by=.EACHI]
    #    char num  bool sum min
    # 1:    A   1  TRUE  12   1
    # 2:    A   2 FALSE   1   1
    # 3:    A   3  TRUE  12   1
    # 4:    B   4 FALSE   9   2
    # 5:    B   5  TRUE   9   2
    # 6:    B   6 FALSE   9   2
    

    要了解by=.EACHI,请查看this post(直到连接的小插曲完成)。

    HTH

    【讨论】:

    【解决方案2】:

    这有点难看,但有效:

    library(data.table)
    library(sqldf)
    
    dt <- data.table(num=c(1, 2, 3, 4, 5, 6), 
                     char=c('A', 'A', 'A', 'B', 'B', 'B'), 
                     bool=c(TRUE, FALSE, TRUE, FALSE, TRUE, FALSE))
    
    dt_two <- data.table(
      num =c(6, 1, 5, 2, 4, 3), 
      char=c('A', 'A', 'A', 'B', 'B', 'B'), 
      bool=c(TRUE, FALSE, TRUE, FALSE, TRUE, FALSE))
    
    
    dt_out_sql <- sqldf('
        select dtone.num,
                dtone.char,
                dtone.bool,
                SUM(dttwo.num) as SUM,  
                MIN(dttwo.num) as MIN
        from    dt as dtone
        INNER join dt_two as dttwo on 
              (dtone.char = dttwo.char) and 
              (dtone.num >= dttwo.num OR dtone.bool)
        GROUP BY dtone.num, dtone.char, dtone.bool
      ')
    
    setDT(dt_out_sql)
    
    setkey(dt, char)
    setkey(dt_two, char)
    
    dt_out_r <- dt[dt_two,
                   list(dtone.num = num,
                        dttwo.num = i.num,
                        char,
                        bool) ,
                   nomatch = 0, allow.cartesian = T
                   ][
                     dtone.num >= dttwo.num | bool,
                     list(SUM = sum(dttwo.num),
                          MIN = min(dttwo.num)),
                     by = list(num = dtone.num,
                               char,
                               bool)
                     ]
    
    setkey(dt_out_r, num, char, bool)
    
    
    all.equal(dt_out_sql, dt_out_r, check.attributes = FALSE)
    

    【讨论】:

    • 我对每个可能的选项进行了基准测试,结果证明这是最快的。在这种情况下,我可以忍受丑陋的。 :)
    【解决方案3】:

    data.table 1.9.8 开始,对于可以放宽连接条件的情况,有如下简单的非等连接语法:

    dt_two[dt, on=.(char, num >= num)]
    

    【讨论】:

    • 这不会返回如here 所示的预期结果,例如
    • 对不起,是的,它没有返回相同结果的原因是因为第二个条件实际上是num &gt;= num OR dtone。据我所知,这在当前 data.table 中无效。但是,对于连接条件更宽松的情况,我仍然认为提及非等连接功能是相关的。
    猜你喜欢
    • 2016-11-12
    • 2013-10-03
    • 2014-03-02
    • 2020-09-16
    • 1970-01-01
    • 2014-03-24
    • 2012-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多