Data.Table非等式连接与算术运算

Ser*_*asa 7 r data.table

我正在尝试对(用于R)大型数据结构(数以千万计的行)进行复杂的自联接,因此我想避免为此操作创建新列,字面上增加了我的对象的内存压力,尤其是因为我想使用不同的加入时间参数。

的结构dt_sample

str(dt_sample)
Classes ‘data.table’ and 'data.frame':  50 obs. of  6 variables:
 $ gateway_airport: chr  "BOS" "BOS" "BOS" "BOS" ...
 $ final_airport  : chr  "ORD" "BNA" "ORD" "RSW" ...
 $ dept_utc       : POSIXct, format: "2016-11-17 15:09:00" "2016-11-17 21:00:00" "2016-11-17 12:40:00" ...
 $ arriv_utc      : POSIXct, format: "2016-11-17 17:03:00" "2016-11-17 23:00:00" "2016-11-17 14:35:00" ...
 $ airlines_id    : chr  "UA" "B6" "UA" "B6" ...
 $ flight_number  : num  1472 1907 449 965 3839 ...
Run Code Online (Sandbox Code Playgroud)

这个想法是在X的final_airport是Y的gateway_airport,Y的dept_utc在X的arriv_UTC的范围内(在下面的示例中,介于+30分钟和+8小时之间)内进行自联接。

这可行,但是创建了一个较大的结构,该结构在合并后会被过滤:

result <- merge(dt_sample, dt_sample, by.x=c("final_airport"),
                by.y=("gateway_airport"))[arriv_utc.x + 1800 <= dept_utc.y 
                                          &arriv_utc.x  +28800 >= dept_utc.y,]
Run Code Online (Sandbox Code Playgroud)

我更喜欢使用这种on = .()表示法,但是它似乎不允许对联接元素进行算术运算,而自联接似乎也将其混淆。同样,我不希望不添加新列。关于如何有效使用data.table的任何想法?

head(result)的结果是一个data.table,每行3个机场,包括起点,中间站点和最终机场(还有一些额外信息)。以下dput中样本的完整结果为19行。

   final_airport gateway_airport          dept_utc.x         arriv_utc.x airlines_id.x flight_number.x final_airport          dept_utc.y         arriv_utc.y
1:           IAD             BOS 2016-11-17 14:35:00 2016-11-17 16:18:00            UA             525           JAX 2016-11-17 17:30:00 2016-11-17 19:37:00
2:           IAD             BOS 2016-11-17 14:35:00 2016-11-17 16:18:00            UA             525           SAV 2016-11-17 17:30:00 2016-11-17 19:16:00
3:           IAD             BOS 2016-11-17 14:35:00 2016-11-17 16:18:00            UA             525           TYS 2016-11-17 17:31:00 2016-11-17 19:10:00
4:           IAD             BOS 2016-11-17 14:35:00 2016-11-17 16:18:00            UA             525           DEN 2016-11-17 17:35:00 2016-11-17 19:36:00
5:           IAD             BOS 2016-11-17 14:35:00 2016-11-17 16:18:00            UA             525           GSO 2016-11-17 17:40:00 2016-11-17 19:09:00
6:           IAD             BOS 2016-11-17 14:35:00 2016-11-17 16:18:00            UA             525           LAX 2016-11-17 17:40:00 2016-11-17 20:25:00
   airlines_id.y flight_number.y
1:            AC            3891
2:            AC            2736
3:            AC            2567
4:            UA             735
5:            AC            2727
6:            UA             632
Run Code Online (Sandbox Code Playgroud)

单击下面以展开50行样本dput结构以提高可重复性:

str(dt_sample)
Classes ‘data.table’ and 'data.frame':  50 obs. of  6 variables:
 $ gateway_airport: chr  "BOS" "BOS" "BOS" "BOS" ...
 $ final_airport  : chr  "ORD" "BNA" "ORD" "RSW" ...
 $ dept_utc       : POSIXct, format: "2016-11-17 15:09:00" "2016-11-17 21:00:00" "2016-11-17 12:40:00" ...
 $ arriv_utc      : POSIXct, format: "2016-11-17 17:03:00" "2016-11-17 23:00:00" "2016-11-17 14:35:00" ...
 $ airlines_id    : chr  "UA" "B6" "UA" "B6" ...
 $ flight_number  : num  1472 1907 449 965 3839 ...
Run Code Online (Sandbox Code Playgroud)

jan*_*cki 3

正如评论中已经解释的,您可以使用非等值连接功能来执行这种连接。由于尚不支持on参数中的动态计算,因此您必须在执行连接之前创建这两列。好处是它不需要任何额外的内存,而且速度非常快。

setDT(dt_sample)

## OP: join, then subset
result <- merge(dt_sample, dt_sample, by.x=c("final_airport"),
                by.y=("gateway_airport"))[arriv_utc.x + 1800 <= dept_utc.y 
                                          &arriv_utc.x  +28800 >= dept_utc.y,]

## efficient: non-equi join
d = copy(dt_sample)
d[, `:=`(arriv_utc2=arriv_utc+1800, arriv_utc3=arriv_utc+28800)]
d[d, nomatch=NULL, on=.(
  final_airport == gateway_airport,
  arriv_utc2 <= dept_utc,
  arriv_utc3 >= dept_utc
  ), j=.(
    x.final_airport, x.gateway_airport, x.dept_utc, x.arriv_utc, x.airlines_id, x.flight_number, i.final_airport, i.dept_utc, i.arriv_utc, i.airlines_id, i.flight_number
  )] -> ans
setnames(result, names(ans))
all.equal(ans, result, check.attributes=FALSE, ignore.row.order=TRUE)
#[1] TRUE
Run Code Online (Sandbox Code Playgroud)