gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 05:58:23 25 4
gpt4 key购买 nike

我正在使用 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

我想获取从 "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

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

x <- data.table[Date >= "01.02.2016 10:00:30  CEST" & Date <= "01.02.2016 10:02:30  CEST"]

但这对我来说太慢了,因为在具有 60 万行的 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"))]

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

最佳答案

数据表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 所提到的,这也计划为非 equi 连接实现 starting from v2.0.0


编辑(26/8/2016):

正如@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

所以如您所见,虽然 bmerge 几乎是即时的,但排序需要花费大量时间。而 between 是最快的,因为它不需要两次将 x 转换为逻辑向量。哎呀,between 太快了,以至于 elapseduser + system

还小

不过,如果您的数据已经排序,那么 inrange 会很好地 catch

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

关于r - 如何在大数据上快速对 data.table 中的多行进行子集化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39016269/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com