重叠连接以计算间隔内的平均值?

overlap join to calculate averages within intervals?

我经常需要在给定的时间间隔 ('events') 内对时间序列数据进行平均,基本上就像被问到的那样 here

正如答案中所建议的,我以 'long' 格式对我的数据使用 SQL 语句。这是一个例子:

#create dummy data frame
set.seed(1)
data <- data.frame(
  date = seq(from = as.POSIXct("2014-01-01 00:00"),
             to = as.POSIXct("2014-01-31 23:00"),
             by = 300),
  A = runif(8917),
  B = runif(8917),
  C = runif(8917),
  D = runif(8917)
)

#convert to long format
require(dplyr)
data <- data %>%
  gather(class,value,A:D)

# create dummy events
events <- data.frame(
  id = c("blue","red","green","yellow"),
  start = as.POSIXct(c("2014-01-03 13:00",
                       "2014-01-12 08:00",
                       "2014-01-18 10:00",
                       "2014-01-27 23:00")),
  stop = as.POSIXct(c("2014-01-03 19:00",
                       "2014-01-13 17:00",
                       "2014-01-20 10:00",
                       "2014-01-28 20:00"))
)


#average value within events, grouped by class
require(sqldf)
results <- sqldf("
     SELECT x.id, y.class, avg(y.value) AS mean 
     FROM events as x, data as y 
     WHERE y.date between x.start and x.stop 
     GROUP BY x.id, y.class
")

给出了所需的输出

       id class      mean
1    blue     A 0.4879129
2    blue     B 0.4945888
3    blue     C 0.5312504
4    blue     D 0.4968260
5   green     A 0.5235671
6   green     B 0.5030602
7   green     C 0.5071219
8   green     D 0.5002010
9     red     A 0.5122966
10    red     B 0.4767966
11    red     C 0.5032387
12    red     D 0.5018389
13 yellow     A 0.4727868
14 yellow     B 0.4626688
15 yellow     C 0.4930207
16 yellow     D 0.5184966

但是由于我的真实数据很大(long format可以达到几百万行),SQL操作需要相当长的时间。

有没有更有效的方法来做这个操作?我偶然发现了 data.table::foverlaps,它被称为 'overlap join',但我不完全明白这是否是我需要的。

如果有一种有效的方法可以将 en 'event' 列添加到数据中,指示每一行(日期)它属于哪个事件,那么我可以使用 dplyr 进行分组汇总,与SQL 语句。但是我不知道该怎么做...

我们将不胜感激专家的任何建议。

更新

正如评论中所建议的,我已将索引的创建添加到我的 SQL 语句中。不幸的是,这并没有加快解决我在现实世界中遇到的一个大问题的速度。计算仍然需要大约 40 分钟才能达到 运行。

然后我复制粘贴了 David 友善提供的 data.table 解决方案,看到它 运行 在完全相同的真实世界数据集上用了不到 1 秒的时间给我留下了深刻的印象。

我仍然不明白它是如何以及为什么这样做的,但我花一些时间学习 data.table 语法的动力肯定增加了很多。再次感谢!

您最好将任务完全卸载到数据库中。看看 RSQLite package. If your data are really large store them in a database like SQLite and get the db to do the subsetting and grouping this should improve the speed of your task. I've written a couple of posts that may help, one on writing to SQLite and one that includes a section on reading from SQLite.

您可能不想这样做的一个原因是,如果您在大量数据集上重复此操作,因为查询速度的提高将随着将数据写入数据库所花费的时间而丢失。

这是一个可能的data.table::foverlaps解决方案

library(data.table)
setDT(data)[, `:=`(start = date, stop = date)]
setkey(setDT(events), start, stop)
foverlaps(data, events, nomatch = 0L)[, .(Mean = mean(value)), keyby = .(id, class)]
#         id class      Mean
#  1:   blue     A 0.4879129
#  2:   blue     B 0.4945888
#  3:   blue     C 0.5312504
#  4:   blue     D 0.4968260
#  5:  green     A 0.5235671
#  6:  green     B 0.5030602
#  7:  green     C 0.5071219
#  8:  green     D 0.5002010
#  9:    red     A 0.5122966
# 10:    red     B 0.4767966
# 11:    red     C 0.5032387
# 12:    red     D 0.5018389
# 13: yellow     A 0.4727868
# 14: yellow     B 0.4626688
# 15: yellow     C 0.4930207
# 16: yellow     D 0.5184966

我觉得逻辑很简单。

  1. data 中的 startstop 列设置为重叠。
  2. key events 数据集的相同列。
  3. 运行 foverlaps 并删除不匹配的间隔 (nomatch = 0L).
  4. 通过idclass计算mean(value)