【问题标题】:How to use specify and extract variables from X and Y in the non-equi join X[Y, ...]?如何在非等值连接 X[Y, ...] 中使用从 X 和 Y 中指定和提取变量?
【发布时间】:2017-06-20 01:19:32
【问题描述】:

这个问题给出了一个示例,说明如何将基本 R merge 语法中的 by.x =by.y = 参数转换为 data.table 语法,以指定不同命名的列作为连接键:

data.table merge by multiple columns

但是,我不知道如何对非 equi 连接执行相同的操作,而且我对输出感到非常困惑。

示例数据:

set.seed(0)
tmp_dt1<- data.table(grp = c(1,2), time = runif(100))
tmp_dt2 <- data.table(grp = c(1,2), time = c(0.1, 0.5))
tmp_dt2 <- tmp_dt2[, time_to := time + 0.2]
tmp_dt2 <- tmp_dt2[, time_from := time] # for clarity, rename time variable

我想通过grp 等值连接这两个表,然后是非等值连接,这样我只保留tmp_dt1 中的time,它位于time_totime_from 之间。据我所知,tmp_dt1[tmp_dt2, , on = c("grp", "time&gt;=time", "time&lt;=time_to")] 做了我想做的事:

> tmp_dt1[tmp_dt2, , on = c("grp", "time>=time", "time<=time_to")]
    grp time time.1 time_from
 1:   1  0.1    0.3       0.1
 2:   1  0.1    0.3       0.1
 3:   1  0.1    0.3       0.1
 4:   1  0.1    0.3       0.1
 5:   1  0.1    0.3       0.1
 6:   1  0.1    0.3       0.1
 7:   1  0.1    0.3       0.1
...

让我困惑的是x.time 不见了,结果列名非常混乱。例如,为什么会有一个名为time.1 的列?我想澄清一下语法,以便tmp_dt1[tmp_dt2, , on = c("grp", "time&gt;=y.time", "time&lt;=y.time_to")] 产生:

    grp y.time y.time_to time_from
 1:   1  0.1    0.3       0.1
 2:   1  0.1    0.3       0.1
 3:   1  0.1    0.3       0.1
 4:   1  0.1    0.3       0.1
 5:   1  0.1    0.3       0.1
 6:   1  0.1    0.3       0.1
 7:   1  0.1    0.3       0.1
...

除了y 中的所有列之外,还有一些方法还提取列x.time。不幸的是,这失败并出现错误:

> tmp_dt1[tmp_dt2, , on = c("grp", "time>=y.time", "time<=y.time_to")]
Error in `[.data.table`(tmp_dt1, tmp_dt2, , on = c("grp", "time>=y.time",  : 
  Column(s) [y.time,y.time_to] not found in i

尝试以下也不会产生我期望的结果,而是得到:

> tmp_dt1[tmp_dt2, .(grp, time, time_from = i.time, time_to = i.time_to), on = c("grp", "time>=time", "time<=time_to")]
    grp time time_from time_to
 1:   1  0.1       0.1     0.3
 2:   1  0.1       0.1     0.3
 3:   1  0.1       0.1     0.3
 4:   1  0.1       0.1     0.3
 5:   1  0.1       0.1     0.3
 6:   1  0.1       0.1     0.3
 7:   1  0.1       0.1     0.3

time 列与 tmp_dt1$time 没有相似之处。

【问题讨论】:

  • 好的,据我所知,如果在X[Y] 中使用.()c() 提供on 条件,则适用以下连接键匹配规则。如果每个元素都包含一个变量,则在两个表中查找该变量。如果在方程的任一侧都提供了变量,则在 X 表中查找 LHS 变量,在 Y 表中查找 RHS 变量。变量提取和最终列名对我来说仍然是个谜。
  • 最后的列名总是来自 Y。on= 中的每个条目都有一个连接列。
  • 您可能想澄清预期的结果。这是一个相当合理的事情:tmp_dt1[tmp_dt1[tmp_dt2, on = .(grp, time &gt;= time_from, time &lt;= time_to), which=TRUE]] 对第一个表进行子集化。我怀疑将下限和上限作为重复值有什么意义。
  • 是的,对不起,我的意思是说最后的列值。连接是x[i](使用实际的参数名称),可以认为是使用i 的行来查找x 的行。出于这个原因,我们最终会在结果中得到来自 i 的值。至少我是这么认为的。对我来说,列名是杂耍,而且很容易定制......
  • 我了解混淆名称(需要修复的东西)。同时,看看this post是否有帮助..

标签: r data.table


【解决方案1】:

为防止混淆,我建议重命名两个 data.tables 中具有相同名称的列,并创建非 equi 连接列的列的副本。

setnames(tmp_dt2, "time", "time_dt2") tmp_dt2[, c("time_from_join", "time_to_join"):=list(time_from, time_to)] tmp_dt1[ , time_join := time]

然后我们可以join然后丢弃所有在non-equi join中被data.table弄乱的临时列。

tmp_dt1[tmp_dt2, on=.(grp==grp, time_join &gt;= time_from_join, time_join &lt;= time_to_join)][ , c("grp", "time", "time_from", "time_to", "time_dt2")]

grp time time_from time_to time_dt2 1: 1 0.1079436 0.1 0.3 0.1 2: 1 0.1216919 0.1 0.3 0.1 3: 1 0.1255551 0.1 0.3 0.1 4: 1 0.1433044 0.1 0.3 0.1 ...

【讨论】:

    【解决方案2】:

    我想你想要这样的东西,使用 dplyr:

    library(dplyr)
    merged <- inner_join(tmp_dt1, tmp_dt2, by="grp") %>%
              rowwise() %>% 
              filter(between(time.x, time_from, time_to)) %>%
              ungroup()
    

    inner_joingrp1 等值连接。 rowwise() 指定我希望以下语句按行出现。 filter() 将按条件过滤行。条件使用between,要求是time.x &gt;= time_fromtime.x &lt;= time_to。最后,ungroup 按行排列,以防您想要正常 data.frame

    【讨论】:

    • 谢谢你,不幸的是,我很确定这种使用 dplyr 的非 equi 连接比 data.table 版本需要更多的内存。
    • 为什么不使用 data.table 连接然后管道到 dplyr 过滤器?
    • data.table 连接(非 equi 部分)已经进行了过滤。无论如何,我的问题是控制连接的输入和输出。
    猜你喜欢
    • 2021-11-22
    • 1970-01-01
    • 2021-04-19
    • 2013-04-22
    • 1970-01-01
    • 2022-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多