R 使用重复键在data.table上滚动联接

R 使用重复键在data.table上滚动联接,r,join,data.table,R,Join,Data.table,我试图理解data.table中的滚动联接。最后给出了重现这一点的数据 给定机场在给定时间的交易数据表: > dt t_id airport thisTime 1: 1 a 5.1 2: 3 a 5.1 3: 2 a 6.2 (注意t_id1和3具有相同的机场和时间) 以及从机场起飞的航班查询表: > dt_lookup f_id airport thisTime 1: 1

我试图理解
data.table
中的
滚动联接。最后给出了重现这一点的数据

给定机场在给定时间的交易数据表:

> dt
   t_id airport thisTime
1:    1       a      5.1
2:    3       a      5.1
3:    2       a      6.2  
(注意
t_id
1和3具有相同的机场和时间)

以及从机场起飞的航班查询表:

> dt_lookup
   f_id airport thisTime
1:    1       a        6
2:    2       a        6
3:    1       b        7
4:    1       c        8
5:    2       d        7
6:    1       d        9
7:    2       e        8

> tables()
     NAME      NROW NCOL MB COLS                  KEY             
[1,] dt           3    3  1 t_id,airport,thisTime airport,thisTime
[2,] dt_lookup    7    3  1 f_id,airport,thisTime airport,thisTime
我想将所有交易与下一个可能从该机场起飞的航班进行匹配,以提供:

   t_id airport thisTime f_id
      1       a        6    1
      1       a        6    2
      3       a        6    1
      3       a        6    2
所以我认为这会起作用:

> dt[dt_lookup, nomatch=0,roll=Inf]
   t_id airport thisTime f_id
1:    3       a        6    1
2:    3       a        6    2
但是它没有返回事务
t\u id==1

从中可以看出:

通常,x的键中不应该有重复项

但是,我的“x键”(即
机场
&
这次
)中确实有重复项,我不能完全理解从输出中删除
t_id=1
意味着什么

谁能解释一下为什么没有返回
t_id=1
,以及当我有重复项时,如何让连接工作

数据

library(data.table)
dt <- data.table(t_id = seq(1:3),
                 airport = c("a","a","a"),
                 thisTime = c(5.1,6.2, 5.1), key=c( "airport","thisTime"))

dt_lookup <- data.table(f_id = c(rep(1,4),rep(2,3)),
                        airport = c("a","b","c","d",
                                 "a","d","e"),
                        thisTime = c(6,7,8,9,
                                 6,7,8), key=c("airport","thisTime"))
库(data.table)

dt输出中没有显示
t_id=1
的原因是滚动联接取最后出现组合键的行。从文件(我的重点):

应用于最后一个联接列,通常是日期,但可以是任意日期 有序变量,不规则,包括间隙。如果roll=TRUE,而我是 行与除最后一个x联接列以外的所有列匹配,其值在 最后一个i连接列落在间隙中(包括最后一个之后 在x中观察该组),则x中的主要值为 向前滚动。使用修改后的 二进制搜索该操作也称为最后一次观察 向前(LOCF)。

让我们考虑一些更大的数据集:

> DT
   t_id airport thisTime
1:    1       a      5.1
2:    4       a      5.1
3:    3       a      5.1
4:    2       d      6.2
5:    5       d      6.2

> DT_LU
   f_id airport thisTime
1:    1       a        6
2:    2       a        6
3:    2       a        8
4:    1       b        7
5:    1       c        8
6:    2       d        7
7:    1       d        9
执行滚动联接时,如您的问题所示:

DT[DT_LU, nomatch=0, roll=Inf]
你会得到:

如您所见,从键组合
a,5.1
d,6.2
中,最后一行用于联接的数据表。因为您使用
Inf
作为滚动值,所以所有未来值都合并到结果数据表中。使用时:

DT[DT_LU, nomatch=0, roll=1]
您可以看到,只包含将来的第一个值:


如果您希望
DT$thisTime
低于
DT\LU$thisTime
的所有
airport
thisTime
组合的
f\u id
,可以通过
上限功能创建新变量(或替换现有的
thisTime
)来实现。例如,我创建了一个新变量
thisTime2
,然后与
DT\u LU
进行正常连接:

DT[, thisTime2 := ceiling(thisTime)]
setkey(DT, airport, thisTime2)[DT_LU, nomatch=0]
其中:

应用于您提供的数据:


当您希望包含所有未来值而不仅仅是第一个值时,您需要一种稍有不同的方法,您需要
i.col
功能(尚未记录):

1:首先仅将键设置为机场
列:

setkey(DT, airport)
setkey(DT_LU, airport)
2:使用
j
中的
i.col
功能(尚未文档化)获得所需内容,如下所示:

DT1 <- DT_LU[DT, .(tid = i.t_id,
                   tTime = i.thisTime,
                   fTime = thisTime[i.thisTime < thisTime],
                   fid = f_id[i.thisTime < thisTime]),
             by=.EACHI]
一些说明:如果要连接使用相同列名的两个数据表,可以通过在列名前面加上
i.
来引用
i
中的数据表列。现在可以将
DT
中的
DT\LU
中的
进行比较。使用
by=.EACHI
可以确保条件保持的所有组合都包含在结果数据表中

或者,您可以通过以下方式实现相同的目标:

DT2 <- DT_LU[DT, .(airport=i.airport,
                   tid=i.t_id,
                   tTime=i.thisTime,
                   fTime=thisTime[i.thisTime < thisTime],
                   fid=f_id[i.thisTime < thisTime]),
             allow.cartesian=TRUE]
如果只希望在特定边界内包含未来值,可以使用:

DT1 <- DT_LU[DT, 
             {
               idx = i.thisTime < thisTime & thisTime - i.thisTime < 2
               .(tid  = i.t_id,
                 tTime = i.thisTime,
                 fTime = thisTime[idx],
                 fid = f_id[idx])
               },
             by=.EACHI]
当您将其与上一个结果进行比较时,您会看到现在第3、6、9、10和12行已被删除


数据:

DT <- data.table(t_id = c(1,4,2,3,5),
                 airport = c("a","a","d","a","d"),
                 thisTime = c(5.1, 5.1, 6.2, 5.1, 6.2),
                 key=c("airport","thisTime"))

DT_LU <- data.table(f_id = c(rep(1,4),rep(2,3)),
                    airport = c("a","b","c","d","a","d","e"),
                    thisTime = c(6,7,8,9,6,7,8),
                    key=c("airport","thisTime"))

DT很好的解释——“滚动连接在键组合最后出现的那一行”——是我理解的关键。谢谢。你的
天花
示例在这种情况下效果很好,但我预计当
dt$thisTime2
值与它试图匹配的
dt\u lookup$thisTime
值的时间单位超过
1
时,它将不起作用,因此我可能不得不想出一个替代方案?我认为这可能是我见过的最好答案之一!感谢您抽出时间介绍一些新技术。@tospig这可能很有趣:我问了一个关于我在解决您的问题时遇到的一些奇怪现象的问题。@tospig基于,我再次更新了我的答案。这些改进将防止您遇到与我遇到的相同的怪事。
DT1 <- DT_LU[DT, .(tid = i.t_id,
                   tTime = i.thisTime,
                   fTime = thisTime[i.thisTime < thisTime],
                   fid = f_id[i.thisTime < thisTime]),
             by=.EACHI]
> DT1
    airport tid tTime fTime 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     7   2
11:       d   2   6.2     9   1
12:       d   5   6.2     7   2
13:       d   5   6.2     9   1
DT2 <- DT_LU[DT, .(airport=i.airport,
                   tid=i.t_id,
                   tTime=i.thisTime,
                   fTime=thisTime[i.thisTime < thisTime],
                   fid=f_id[i.thisTime < thisTime]),
             allow.cartesian=TRUE]
> identical(DT1, DT2)
[1] TRUE
DT1 <- DT_LU[DT, 
             {
               idx = i.thisTime < thisTime & thisTime - i.thisTime < 2
               .(tid  = i.t_id,
                 tTime = i.thisTime,
                 fTime = thisTime[idx],
                 fid = f_id[idx])
               },
             by=.EACHI]
> DT1
   airport tid tTime fTime 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
DT <- data.table(t_id = c(1,4,2,3,5),
                 airport = c("a","a","d","a","d"),
                 thisTime = c(5.1, 5.1, 6.2, 5.1, 6.2),
                 key=c("airport","thisTime"))

DT_LU <- data.table(f_id = c(rep(1,4),rep(2,3)),
                    airport = c("a","b","c","d","a","d","e"),
                    thisTime = c(6,7,8,9,6,7,8),
                    key=c("airport","thisTime"))