R中时间序列数据的滑动时间间隔
Posted
技术标签:
【中文标题】R中时间序列数据的滑动时间间隔【英文标题】:Sliding time intervals for time series data in R 【发布时间】:2012-05-15 00:16:38 【问题描述】:我正在尝试为不规则的时间序列数据集提取有趣的统计数据,但未能找到适合该工作的工具。很容易找到用于处理任何时间定期采样的时间序列或基于索引的序列的工具,尽管我在尝试解决的问题上运气不佳。
首先,一个可重现的数据集:
library(zoo)
set.seed(0)
nSamples <- 5000
vecDT <- rexp(nSamples, 3)
vecTimes <- cumsum(c(0,vecDT))
vecDrift <- c(0, rnorm(nSamples, mean = 1/nSamples, sd = 0.01))
vecVals <- cumsum(vecDrift)
vecZ <- zoo(vecVals, order.by = vecTimes)
rm(vecDT, vecDrift)
假设时间以秒为单位。 vecZ
系列中有近 1700 秒(仅 30 分钟),在此期间有 5001 个条目。 (注意:我会尝试使用xts
,但xts
似乎需要日期信息,我宁愿在不相关时不使用特定日期。)
我的目标如下:
确定每个点之前 3 分钟和之后 3 分钟的值的索引。由于时间是连续的,我怀疑任何两点之间恰好相隔 3 分钟。我想找到的是在给定点之前最多 3 分钟和之后至少 3 分钟的点,即类似于以下内容(在伪代码中):
backIX(t, vecZ, tDelta) = minix in length(vecZ) : t - time(ix) < tDelta
forwardIX(t, vecZ, tDelta) = minix in length(vecZ) : time(ix) - t > tDelta
所以,在 3 分钟内,tDelta = 180
。如果t=2500
,那么forwardIX()
的结果将是 3012(即 time(vecZ)[2500] 是 860.1462,time(vecZ)[3012] 是 1040.403,或者刚刚超过 180 秒),并且输出backwardIX()
将是 2020 年(对应于时间 680.7162 秒)。
理想情况下,我想使用不需要t
的函数,因为这将需要对函数进行length(vecZ)
调用,这忽略了可以更有效地计算滑动时间窗口这一事实。
将函数应用于滚动时间窗口中的所有值。我见过rollapply
,它采用固定的窗口大小(即固定数量的索引,但不是固定的时间窗口)。我可以用一个简单的方法来解决这个问题,用一个循环(或foreach
;-))来计算每个索引t
,但我想知道是否已经实现了一些简单的功能,例如计算给定时间范围内所有值的平均值的函数。由于这可以通过在窗口上滑动的简单汇总统计信息有效地完成,因此它在计算上应该比多次访问所有数据以计算每个统计信息的函数更便宜。一些相当自然的函数:均值、最小值、最大值和中值。
即使窗口不随时间变化,改变窗口大小的能力也足够了,我可以使用上述问题的结果找到窗口大小。但是,这似乎仍然需要进行过多的计算,因此能够指定基于时间的间隔似乎更有效。
R 中是否存在有助于在时间窗口中对数据进行此类操作的包,还是我运气不好,我应该编写自己的函数?
注 1:This question 试图做类似的事情,除了不相交的间隔,而不是滚动的时间窗口,例如我可以调整它以对每个连续的 3 分钟块进行分析,但我没有看到一种方法可以调整它以滚动 3 分钟间隔。
注意 2:我发现从 zoo
对象切换到数字向量(对于时代而言)显着加快了第一个目标的范围查找/窗口端点识别问题。这仍然是一种幼稚的算法,但值得一提的是,使用 zoo
对象可能不是幼稚方法的最佳选择。
【问题讨论】:
我认为xts
可能是要走的路。请参阅?endpoints
、?to.period
、?period.apply
和 ?split.xts
。像这样将您的对象强制为 xts:x <- .xts(vecVals, vecTimes)
@GSee 谢谢,尽管在我看来,这些函数将数据拆分为连续的、不相交的间隔(如我附加到问题的注释中所述)。如果有办法制作滑动/滚动时间窗口,我还没有弄清楚如何让xts
做到这一点。
您可以合并一个零宽度的严格规则 xts 对象和na.locf
以使您的数据严格规则。然后使用rollapply
@GSee 你难倒我了。 :) 我还没有看到它是如何工作的,但我会考虑更多。我现在看到 rollapply
支持 width
作为列表 - 我想我只需要弄清楚如何获取该列表。
嗯。如果你想保持微秒时间戳,我的方法会让你的对象变得更大,更大。我应该重新考虑..
【参考方案1】:
这是我的建议,但我不确定它是否能准确回答您的问题
#Picking up where your code left off
library(xts)
library(TTR)
x <- .xts(vecZ, vecTimes)
xx <- na.locf(cbind(xts(, seq.POSIXt(from=start(x), to=end(x), by='sec')), x))
x$means <- runMean(xx, n=180)
out <- x[!is.na(x[, 1]), ]
tail(out)
x means
1969-12-31 18:28:17.376141 0.2053531 0.1325938
1969-12-31 18:28:17.379140 0.2101565 0.1329065
1969-12-31 18:28:17.619840 0.2139770 0.1332403
1969-12-31 18:28:17.762765 0.2072574 0.1335843
1969-12-31 18:28:17.866473 0.2065790 0.1339608
1969-12-31 18:28:17.924270 0.2114755 0.1344264
【讨论】:
【参考方案2】:从 v1.9.8 版开始(CRAN 2016 年 11 月 25 日),data.table 已获得在非等值连接中聚合的能力,可用于在不规则时间序列的滑动时间窗口。
为了演示和验证,使用了较小的数据集。
library(data.table) # development version 1.11.9 used
# create small dataset
set.seed(0)
nSamples <- 10
vecDT <- rexp(nSamples, 3)
vecTimes <- cumsum(c(0,vecDT))
vecVals <- 0:nSamples
vec <- data.table(vecTimes, vecVals)
vec
vecTimes vecVals 1: 0.00000000 0 2: 0.06134553 1 3: 0.10991444 2 4: 0.15651286 3 5: 0.30186907 4 6: 1.26685858 5 7: 1.67671260 6 8: 1.85660688 7 9: 2.17546271 8 10: 2.22447804 9 11: 2.68805641 10
# define window size in seconds
win_sec = 0.3
# aggregate in sliding window by a non-equi join
vec[.(t = vecTimes, upper = vecTimes + win_sec, lower = vecTimes - win_sec),
on = .(vecTimes < upper, vecTimes > lower),
.(t, .N, sliding_mean = mean(vecVals)), by = .EACHI]
vecTimes vecTimes t N sliding_mean 1: 0.3000000 -0.300000000 0.00000000 4 1.5 2: 0.3613455 -0.238654473 0.06134553 5 2.0 3: 0.4099144 -0.190085564 0.10991444 5 2.0 4: 0.4565129 -0.143487143 0.15651286 5 2.0 5: 0.6018691 0.001869065 0.30186907 4 2.5 6: 1.5668586 0.966858578 1.26685858 1 5.0 7: 1.9767126 1.376712596 1.67671260 2 6.5 8: 2.1566069 1.556606875 1.85660688 2 6.5 9: 2.4754627 1.875462707 2.17546271 2 8.5 10: 2.5244780 1.924478037 2.22447804 2 8.5 11: 2.9880564 2.388056413 2.68805641 1 10.0
前两列分别显示了时间间隔的上限和下限,t
是原始的vecTimes
,N
表示计算滑动平均值时包含的数据点的数量。
【讨论】:
以上是关于R中时间序列数据的滑动时间间隔的主要内容,如果未能解决你的问题,请参考以下文章