我经常需要在给定的时间间隔(“事件”)内平均时间序列数据,基本上就像被问到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
然而,由于我的真实数据很大(长格式可能达到数百万行),SQL操作需要相当长的时间。
有更有效的方法来执行此操作吗?我在data.table::foverlaps
中遇到了问题,这被称为“重叠加入”,但我不完全明白这是否是我需要的。
如果有一种有效的方法将en'event'列添加到数据中,指示每一行(日期),它指向哪个事件,那么我可以使用dplyr比较SQL语句进行分组摘要。但我不知道该怎么做......
非常感谢专家的任何建议。
更新
正如评论中所建议的,我已经为我的SQL语句添加了索引的创建。不幸的是,这并没有为我的一个大的现实问题加速。计算仍需要约40分钟才能运行。
然后我复制粘贴了David提供的data.table解决方案,并且看到它在完全相同的真实数据集上运行不到1秒就给人留下了深刻的印象。
我仍然不明白它是如何以及为什么会这样做的,但是我花费一些时间学习data.table语法的动机肯定会增加很多。再次感谢!
答案 0 :(得分:2)
这是一个可能的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
这个逻辑对我来说非常简单。
start
内的stop
和data
列设置为重叠。key
由相同列设置的events
数据。foverlaps
并删除不匹配的时间间隔(nomatch = 0L
)。mean(value)
和id
class
醇>
答案 1 :(得分:-1)
您最好将任务完全卸载到数据库中。看看RSQLite package。如果您的数据非常大,则将它们存储在SQLite等数据库中,并让数据库进行子集化和分组,这样可以提高任务的速度。我已经撰写了一些可能有用的帖子,一篇在writing to SQLite,一篇包含reading from SQLite部分。
您可能不希望这样做的一个原因是,如果您在许多数据集上重复此操作,因为在将数据写入数据库所花费的时间内,查询的速度提升将会丢失。