不规则时间序列的滚动窗口

11

我有一个使用xts的非规则时间序列事件(帖子),我想计算在滚动的每周窗口(或两周、三天等)内发生的事件数量。数据看起来像这样:

                    postid
2010-08-04 22:28:07    867
2010-08-04 23:31:12    891
2010-08-04 23:58:05    901
2010-08-05 08:35:50    991
2010-08-05 13:28:02   1085
2010-08-05 14:14:47   1114
2010-08-05 14:21:46   1117
2010-08-05 15:46:24   1151
2010-08-05 16:25:29   1174
2010-08-05 23:19:29   1268
2010-08-06 12:15:42   1384
2010-08-06 15:22:06   1403
2010-08-07 10:25:49   1550
2010-08-07 18:58:16   1596
2010-08-07 21:15:44   1608

应该产生类似以下的结果

                    nposts
2010-08-05 00:00:00     10
2010-08-06 00:00:00      9
2010-08-07 00:00:00      5

针对一个两天的时间窗口,我查看了rollapplyapply.rolling等函数(从PerformanceAnalytics库中获取),它们都假设数据是定期时间序列。我试过将所有时间转换为帖子发生的那一天,然后使用像ddply这样的函数按每天进行分组,这让我接近目标了。但是,用户可能不会每天都发帖,因此时间序列仍然是不规则的。我可以用0来填补空缺,但这可能会大幅增加我的数据量,而且已经很庞大了。

我该怎么办?


4
目前 xts 软件包中并没有解决此问题的方法,但是由于这个请求已经出现了足够多的次数,我已经开始考虑提供一个解决方案。 - Joshua Ulrich
你有更新吗,@JoshuaUlrich?或者类似下面答案的内容,可以用零或NA数据填充缺失的天数,这样我们就可以使用rollapply了。我猜我可以使用merge... - flodel
@flodel:这个问题并不需要我所想的那样(请看我的回答)。我原以为他们想要在原始序列中回溯n天的每个观测值,这是一个更加困难的问题需要解决。 - Joshua Ulrich
嗯,我必须承认我没有仔细阅读问题,只停留在标题上。我确实正在寻找更复杂的情况。我的数据不是非常稀疏,所以我将使用“merge”使时间序列变得规则。 - flodel
3个回答

5
这里有一个使用xts的解决方案:
x <- structure(c(867L, 891L, 901L, 991L, 1085L, 1114L, 1117L, 1151L, 
  1174L, 1268L, 1384L, 1403L, 1550L, 1596L, 1608L), .Dim = c(15L, 1L),
  index = structure(c(1280960887, 1280964672, 1280966285, 
  1280997350, 1281014882, 1281017687, 1281018106, 1281023184, 1281025529, 
  1281050369, 1281096942, 1281108126, 1281176749, 1281207496, 1281215744),
  tzone = "", tclass = c("POSIXct", "POSIXt")), class = c("xts", "zoo"),
  .indexCLASS = c("POSIXct", "POSIXt"), tclass = c("POSIXct", "POSIXt"),
  .indexTZ = "", tzone = "")
# first count the number of observations each day
xd <- apply.daily(x, length)
# now sum the counts over a 2-day rolling window
x2d <- rollapply(xd, 2, sum)
# align times at the end of the period (if you want)
y <- align.time(x2d, n=60*60*24)  # n is in seconds

4

看起来这个可以工作:

# n = number of days
n <- 30
# w = window width. In this example, w = 7 days
w <- 7

# I will simulate some data to illustrate the procedure
data <- rep(1:n, rpois(n, 2))

# Tabulate the number of occurences per day:
# (use factor() to be sure to have the days with zero observations included)
date.table <- table(factor(data, levels=1:n))  

mat <- diag(n)
for (i in 2:w){
  dim <- n+i-1
  mat <- mat + diag(dim)[-((n+1):dim),-(1:(i-1))]
  }

# And the answer is.... 
roll.mean.7days <- date.table %*% mat

看起来速度不会太慢(尽管mat矩阵的维数将为n*n)。 我尝试用n = 3000替换n = 30(这将创建一个包含900万个元素= 72 MB的矩阵),在我的计算机上仍然相当快。 对于非常大的数据集,首先尝试使用子集... 使用Matrix包中的一些函数(bandSparse)创建mat矩阵也会更快。


这是一种很好的将滚动窗口应用于某些内容的方法,但如果您不提供一个示例来展示如何将其应用于实际时间序列(如原始问题中表示为POSIXct日期时间对象),那么它几乎无法回答问题。 - plannapus
使用不规则间隔的POSIXct对象向量data <- sample(seq(as.POSIXct("2012/01/01"),as.POSIXct("2012/01/31"),by="hours"), 30),您可以通过以下方式替换您的date.table行:date.table <- table(cut(data,"days")),然后按照您之前的方式继续操作,这应该就可以解决问题了。 - plannapus
plannapus,感谢您对 POSIXct 对象的补充。 - Dag Hjermann
有什么简单的方法来扩展这个功能,不仅可以对帖子数量进行求和,还可以包括因素 - 例如发帖人数量...? - puslet88

0

使用runner,可以在滚动窗口上应用任何R函数。 OP需要的是仅在指定时间点上计算滚动窗口上的函数(长度)。 使用 runner ,用户需要指定 at 参数,以指示应在哪些时间点计算输出。我们可以将时间点的向量传递给我们在一侧创建的 runner 作为 POSIXt 序列。
要使 runner 时间相关,必须通过与 x 对象对应的日期指定 idx 。窗口的长度可以设置为 k =“2天”

at <- seq(as.POSIXct("2010-08-05 00:00:00"), 
          by = "1 days",
          length.out = 4)

# [1] "2010-08-05 CEST" "2010-08-06 CEST" "2010-08-07 CEST" "2010-08-08 CEST"


runner::runner(
  x = x$postid,
  k = "2 days",
  idx = x$datetime,
  at = at,
  f = length
)
# [1]  3 10  9  5


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接