data.table v1.9.7+ 实现了non-equi joins 并添加了一个新功能inrange 使用这个新功能,可以实现你想要的
## Loading data
library(data.table) #v 1.9.7+
DT <- data.table(date = c('01.02.2016 10:00:00','01.02.2016 10:01:00',
'01.02.2016 10:02:00','01.02.2016 10:03:00',
'01.02.2016 10:04:00'),
column1 = c(10, 12, 13, 11, 17))
## Converting to POSIXct class
DT[, date := as.POSIXct(date, format = "%d.%m.%Y %H:%M:%S")]
## Validating that forder/bmerge kicks in
options(datatable.verbose = TRUE)
DT[date %inrange% as.POSIXct(c("2016-02-01 10:00:30", "2016-02-01 10:02:30"))]
# forderv(query) took ... 0 secs
# Starting bmerge ...done in 0 secs <~~~~~~~~ (Thanks to @Arun for fixing the bug)
# Generating final logical vector ... done in 0 secs
# date column1
# 1: 2016-02-01 10:01:00 12
# 2: 2016-02-01 10:02:00 13
不过,您应该知道,自从实现了 data.table 1.9.4 secondary keys,这意味着对于矢量扫描的某些变体,在第一次运行后添加一个键,从现在开始,即使是诸如== 和 %in% 正在使用 bmerge。这似乎不适用于POSIXct 类,但您可以在数字列column1 上观察到这种行为@
## Running for first time
options(datatable.verbose = TRUE)
DT[column1 == 10]
# Creating new index 'column1'
# forder took 0 sec <~~~ forder kicks in, hence first time is a bit slow
# Starting bmerge ...done in 0 secs
# date column1
# 1: 2016-02-01 10:00:00 10
## Running for second time and on
DT[column1 == 10]
# Using existing index 'column1'
# Starting bmerge ...done in 0 secs <~~ bmerge kicks in from now on
# date column1
# 1: 2016-02-01 10:00:00 10
正如@Jan 提到的,这也计划用于非等连接starting from v2.0.0
编辑(2016 年 8 月 26 日):
正如@Arun 所指出的,虽然inrange 使用二元连接,但它需要先对整个向量进行排序,以检查x 中的每个 值是否在any 之间 的区间提供在下、上。
在您的情况下,这有点开销,因为您只比较两个值,因此最近用 C 重写的 between 函数将更适合您
set.seed(123)
DT <- data.table(x = sample(5e8))
system.time(res1 <- DT[x > 1e3L & x < 1e5L])
# user system elapsed
# 10.23 1.22 11.45
system.time(res2 <- DT[x %inrange% c(1e3L, 1e5L)])
# forderv(query) took ... 29.09 secs
# Starting bmerge ...done in 0 secs
# Generating final logical vector ... done in 0.43 secs
# user system elapsed
# 29.28 0.70 30.06
system.time(res3 <- DT[x %between% c(1e3L, 1e5L)])
# user system elapsed
# 2.01 2.60 0.84
如您所见,虽然bmerge 几乎是即时的,但排序需要很多时间。而between 是最快的,因为它不需要将x 转换为逻辑向量两次。哎呀,between 如此之快以至于elapsed 比user + system 更小
不过,如果您的数据已经排序,那么 inrange 可以很好地赶上
setorder(DT, x)
system.time(res1 <- DT[x > 1e3L & x < 1e5L])
# user system elapsed
# 10.41 1.02 11.45
system.time(res2 <- DT[x %inrange% c(1e3L, 1e5L)])
# forderv(query) took ... 2.17 secs
# Starting bmerge ...done in 0 secs
# Generating final logical vector ... done in 0.44 secs
# user system elapsed
# 2.47 0.71 3.20
system.time(res3 <- DT[x %between% c(1e3L, 1e5L)])
# user system elapsed
# 2.30 2.62 0.88