使用重复键

时间:2015-08-14 09:46:30

标签: r join data.table

我正在尝试理解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"))

1 个答案:

答案 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.1d, 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