首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于时间窗的不规则时间序列滚动函数的优化

基于时间窗的不规则时间序列滚动函数的优化
EN

Stack Overflow用户
提问于 2013-04-12 07:02:45
回答 5查看 3.6K关注 0票数 26

有没有办法使用rollapply (来自zoo包或类似的)优化函数(rollmeanrollmedian等)来计算基于时间的窗口的滚动函数,而不是基于大量观察的滚动函数?我想要的很简单:对于不规则时间序列中的每个元素,我想计算一个具有N天窗口的滚动函数。也就是说,该窗口应包括当前观察值之前N天内的所有观察值。时间序列也可能包含重复项。

下面是一个例子。给定以下时间序列:

代码语言:javascript
复制
      date  value
 1/11/2011      5
 1/11/2011      4
 1/11/2011      2
 8/11/2011      1
13/11/2011      0
14/11/2011      0
15/11/2011      0
18/11/2011      1
21/11/2011      4
 5/12/2011      3

具有5天窗口的滚动中位数,右对齐,应得到以下计算结果:

代码语言:javascript
复制
> c(
    median(c(5)),
    median(c(5,4)),
    median(c(5,4,2)),
    median(c(1)),
    median(c(1,0)), 
    median(c(0,0)),
    median(c(0,0,0)),
    median(c(0,0,0,1)),
    median(c(1,4)),
    median(c(3))
   )

 [1] 5.0 4.5 4.0 1.0 0.5 0.0 0.0 0.0 2.5 3.0

我已经找到了一些解决方案,但它们通常很棘手,这通常意味着速度很慢。我设法实现了我自己的滚动函数计算。问题是,对于非常长的时间序列,优化版本的中位数(滚动中值)可能会产生巨大的时间差,因为它考虑了窗口之间的重叠。我希望避免重新实现它。我怀疑使用rollapply参数会有一些技巧可以让它工作,但我不能弄明白。提前感谢你的帮助。

EN

回答 5

Stack Overflow用户

发布于 2018-12-26 21:54:44

从1.9.8版本开始(2016年11月25日),data.table已经获得了执行非对等连接的能力,可以在这里使用。

操作员已请求

对于不规则时间序列中的每个元素,我希望计算一个具有N天窗口的滚动函数。也就是说,该窗口应包括当前观察值之前N天内的所有观察值。时间序列也可能包含重复项。

请注意,OP已要求包括当前观测前N天内的所有观测。这与在当天之前的N天内请求所有观察结果不同。

对于后者,我希望1/11/2011有一个值,即median(c(5, 4, 2)) = 4。

显然,OP期望一个基于观察的滚动窗口,限制为N天。因此,非equi join的联接条件也必须考虑行数。

代码语言:javascript
复制
library(data.table)
n_days <- 5L
setDT(DT)[, rn := .I][
  .(ur = rn, ud = date, ld = date - n_days), 
  on = .(rn <= ur, date <= ud, date >= ld),
  median(as.double(value)), by = .EACHI]$V1

1 5.0 4.5 4.0 1.0 0.5 0.0 0.0 0.0 2.5 3.0

为了完整起见,基于天的滚动窗口的可能解决方案可以是:

代码语言:javascript
复制
setDT(DT)[.(ud = unique(date), ld = unique(date) - n_days), on = .(date <= ud, date >= ld), 
   median(as.double(value)), by = .EACHI]

date date V1 1: 2011-11-01 2011-10-27 4.0 2: 2011-11-08 2011-11-03 1.0 3: 2011-11-13 2011-11-08 0.5 4: 2011-11-14 2011-11-09 0.0 5: 2011-11-15 2011-11-10 0.0 6: 2011-11-18 2011-11-13 0.0 7: 2011-11-21 2011-11-16 2.5 8: 2011-12-05 2011-11-30 3.0

数据

代码语言:javascript
复制
library(data.table)
DT <- fread("      date  value
 1/11/2011      5
 1/11/2011      4
 1/11/2011      2
 8/11/2011      1
13/11/2011      0
14/11/2011      0
15/11/2011      0
18/11/2011      1
21/11/2011      4
 5/12/2011      3")[
   # coerce date from character string to integer date class
   , date := as.IDate(date, "%d/%m/%Y")]
票数 5
EN

Stack Overflow用户

发布于 2015-11-24 21:10:37

1) 没有检查速度,但如果没有日期超过max.dup次,则必须是最后5* max.dup条目包含最近5天,所以下面显示的传递给rollapplyr的一行函数fn将执行此操作:

代码语言:javascript
复制
k <- 5

dates <- as.numeric(DF$date)
values <- DF$value

max.dup <- max(table(dates))

fn <- function(ix, d = dates[ix], v = values[ix], n = length(ix)) median(v[d >= d[n]-k])

rollapplyr(1:nrow(DF), max.dup * k, fn, partial = TRUE)
## [1] 5.0 4.5 4.0 1.0 0.5 0.0 0.0 0.0 2.5 3.0

sqldf我们可以使用自连接来实现这一点。我们将那些不超过5天的b行连接到每个a行,然后按a行进行分组,取与其连接的b行的中值。

代码语言:javascript
复制
library(sqldf)

k <- 5
res <- fn$sqldf("select a.date, a.value, median(b.value) median
       from DF a
       left join DF b on b.date between a.date - $k and a.date and b.rowid <= a.rowid
       group by a.rowid")

给予:

代码语言:javascript
复制
res$median
## [1] 5.0 4.5 4.0 1.0 0.5 0.0 0.0 0.0 2.5 3.0

注意:我们在DF中使用了这个

代码语言:javascript
复制
 Lines <- "
      date  value
 1/11/2011      5
 1/11/2011      4
 1/11/2011      2
 8/11/2011      1
13/11/2011      0
14/11/2011      0
15/11/2011      0
18/11/2011      1
21/11/2011      4
 5/12/2011      3
"
DF <- read.table(text = Lines, header = TRUE)
DF$date <- as.Date(DF$date, format = "%d/%m/%Y")
票数 3
EN

Stack Overflow用户

发布于 2019-10-27 19:34:22

我推荐使用runner包,该包针对本主题中要求的操作进行了优化。有关详细说明,请转到根据documentation中的date的窗口一节。

为了解决你的任务,你可以使用runner函数,它可以在windows运行时执行任何R函数。这里有一行代码:

代码语言:javascript
复制
df <- read.table(
  text = "date  value
   2011-11-01      5
   2011-11-01      4
   2011-11-01      2
   2011-11-08      1
   2011-11-13      0
   2011-11-14      0
   2011-11-15      0
   2011-11-18      1
   2011-11-21      4
   2011-12-05      3", header = TRUE, colClasses = c("Date", "integer"))

library(runner)
runner(df$value, k = 5, idx = df$date, f = median)
[1] 5.0 4.5 4.0 1.0 0.0 0.0 0.0 0.0 2.5 3.0

附注:人们应该知道,5天窗口是[i-4, i-3, i-2, i-1, i]而不是(i-5):i (6天窗口)。下面的插图更好地解释了这个概念。

我已经在5天窗口上做了一个例子,但是如果你想按照OP的要求重现结果,可以指定6天窗口:

代码语言:javascript
复制
identical(
  runner(df$value, k = 6, idx = df$date, f = median),
  c(5.0, 4.5, 4.0, 1.0, 0.5, 0.0, 0.0, 0.0, 2.5, 3.0)
)
# [1] TRUE
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15960352

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档