我正在尝试理解rolling joins
中的data.table
。最后给出了重现这一点的数据。
给出机场交易的数据表,在给定时间:
> dt
t_id airport thisTime
1: 1 a 5.1
2: 3 a 5.1
3: 2 a 6.2
(注意t_ids
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_id == 1
。
来自the documentation它说:
通常,x的键中不应有重复,......
但是,我的'x key'(即airport
& thisTime
)中确实存在重复项,并且无法完全看清楚了解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"))
答案 0 :(得分:22)
t_id = 1
未出现在输出中的原因是滚动连接占用了最后出现组合键的行。从文档(强调我的):
适用于上一个连接列,通常是日期,但可以是任何日期 有序变量,不规则且包括间隙。如果roll = TRUE且我是 行匹配除了最后一个x连接列之外的所有列,以及它的值 最后我加入专栏落在一个缺口(包括在最后一个之后) 在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]
你得到:
t_id airport thisTime f_id
1: 3 a 6 1
2: 3 a 6 2
3: 3 a 8 2
4: 5 d 7 2
5: 5 d 9 1
如您所见,从组合a, 5.1
和d, 6.2
开始,最后一行用于连接的数据表。由于您使用Inf
作为滚动值,因此所有未来值都包含在生成的数据表中。当你使用:
DT[DT_LU, nomatch=0, roll=1]
您会看到只包含未来的第一个值:
t_id airport thisTime f_id
1: 3 a 6 1
2: 3 a 6 2
3: 5 d 7 2
如果您希望f_id
用于airport
&amp;的所有组合thisTime
DT$thisTime
DT_LU$thisTime
低于thisTime
,您可以通过ceiling
函数创建新变量(或替换现有thisTime2
)来实现这一目标。我创建新变量DT_LU
然后与DT[, thisTime2 := ceiling(thisTime)]
setkey(DT, airport, thisTime2)[DT_LU, nomatch=0]
进行常规联接的示例:
t_id airport thisTime thisTime2 f_id
1: 1 a 5.1 6 1
2: 4 a 5.1 6 1
3: 3 a 5.1 6 1
4: 1 a 5.1 6 2
5: 4 a 5.1 6 2
6: 3 a 5.1 6 2
7: 2 d 6.2 7 2
8: 5 d 6.2 7 2
给出:
> dt[, thisTime2 := ceiling(thisTime)]
> setkey(dt, airport, thisTime2)[dt_lookup, nomatch=0]
t_id airport thisTime thisTime2 f_id
1: 1 a 5.1 6 1
2: 3 a 5.1 6 1
3: 1 a 5.1 6 2
4: 3 a 5.1 6 2
应用于您提供的数据:
i.col
当您想要包含未来值而不是仅包含第一个值时,您需要一种稍微不同的方法,您需要airport
功能(尚未记录):
1 :首先将密钥设置为仅setkey(DT, airport)
setkey(DT_LU, airport)
列:
i.col
2 :使用j
中的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
这会给你:
i
一些解释:如果您要连接两个使用相同列名的数据表,您可以通过在列名前面加i.
来引用thisTime
中数据表的列。现在,可以将DT
的{{1}}与thisTime
的{{1}}进行比较。使用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]
如果您只想在某个边界内包含未来值,可以使用:
> 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]
当您将其与之前的结果进行比较时,您会看到现在已删除第3,6,9,10和12行。
数据:强>
> 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