有没有办法使用rollapply (来自zoo包或类似的)优化函数(rollmean,rollmedian等)来计算基于时间的窗口的滚动函数,而不是基于大量观察的滚动函数?我想要的很简单:对于不规则时间序列中的每个元素,我想计算一个具有N天窗口的滚动函数。也就是说,该窗口应包括当前观察值之前N天内的所有观察值。时间序列也可能包含重复项。
下面是一个例子。给定以下时间序列:
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天窗口的滚动中位数,右对齐,应得到以下计算结果:
> 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参数会有一些技巧可以让它工作,但我不能弄明白。提前感谢你的帮助。
发布于 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的联接条件也必须考虑行数。
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]$V11 5.0 4.5 4.0 1.0 0.5 0.0 0.0 0.0 2.5 3.0
为了完整起见,基于天的滚动窗口的可能解决方案可以是:
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
数据
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")]发布于 2015-11-24 21:10:37
1) 没有检查速度,但如果没有日期超过max.dup次,则必须是最后5* max.dup条目包含最近5天,所以下面显示的传递给rollapplyr的一行函数fn将执行此操作:
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.0sqldf我们可以使用自连接来实现这一点。我们将那些不超过5天的b行连接到每个a行,然后按a行进行分组,取与其连接的b行的中值。
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")给予:
res$median
## [1] 5.0 4.5 4.0 1.0 0.5 0.0 0.0 0.0 2.5 3.0注意:我们在DF中使用了这个
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")发布于 2019-10-27 19:34:22
我推荐使用runner包,该包针对本主题中要求的操作进行了优化。有关详细说明,请转到根据documentation中的date的窗口一节。
为了解决你的任务,你可以使用runner函数,它可以在windows运行时执行任何R函数。这里有一行代码:
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天窗口:

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] TRUEhttps://stackoverflow.com/questions/15960352
复制相似问题