如何在大数据上快速从data.table中对多行进行子集化

Len*_*nie 2 r data.table

我正在使用R-Studio并希望从data.table中获取多行.

假设我有一个data.table,包含以下数据:

Date                           Column 1
"01.02.2016 10:00:00  CEST"    10        
"01.02.2016 10:01:00  CEST"    12
"01.02.2016 10:02:00  CEST"    13
"01.02.2016 10:03:00  CEST"    11
"01.02.2016 10:04:00  CEST"    17
Run Code Online (Sandbox Code Playgroud)

我希望得到的值从"01.02.2016 10:00:30""01.02.2016 10:02:30",如下所示:

    Date                       Column 1       
"01.02.2016 10:01:00  CEST"    12
"01.02.2016 10:02:00  CEST"    13
Run Code Online (Sandbox Code Playgroud)

目前我通过这样做实现这一目标:

x <- data.table[Date >= "01.02.2016 10:00:30  CEST" & Date <= "01.02.2016 10:02:30  CEST"]
Run Code Online (Sandbox Code Playgroud)

但这对我来说太慢了,因为在一个600k行的data.table上需要大约0.4秒.

相反,这要快得多:

setkey(data.table, Date)
x <- prozessdaten.data.table[J(c("01.02.2016 10:01:00  CEST", "01.02.2016 10:02:00  CEST"))]
Run Code Online (Sandbox Code Playgroud)

我的问题是否有可能使用具有指定时间范围而不是确切值的二进制搜索函数J()?

Dav*_*urg 11

data.table v1.9.7 +实现了非equi连接并添加了一个新功能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
Run Code Online (Sandbox Code Playgroud)

但是,您应该知道,因为data.table 1.9.4 辅助密钥已经实现,这意味着对于矢量扫描的某些变体,在第一次运行之后,正在添加一个密钥,从现在开始,即使是诸如==%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
Run Code Online (Sandbox Code Playgroud)

如前所述通过@Jan,这个计划对于非球菌中实现联接也从V2.0.0开始


编辑(2016年6月26日):

正如@Arun所指出的,虽然inrange使用二进制连接,但它需要首先对整个向量进行排序,以便检查x中的每个值是否介于lower,upper中提供的任何时间间隔之间.在你的情况下,它只是一个开销,因为你只是比较两个值,因此最近重写的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
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,虽然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 
Run Code Online (Sandbox Code Playgroud)

  • 更多操作的自动索引目前计划为2.0.0 - [data.table#1068](https://github.com/Rdatatable/data.table/issues/1068) (3认同)
  • @Arun [修复了bug](https://github.com/Rdatatable/data.table/issues/1819)所以现在你可以看到`bmerge`踢了更新帖子.你需要Gh的最新版本 (2认同)