可以处理重复的不规则时间序列的滚动窗口函数

标签 r date time-series rolling-computation

我有以下数据框:

    grp  nr   yr
 1:   A 1.0 2009
 2:   A 2.0 2009
 3:   A 1.5 2009
 4:   A 1.0 2010
 5:   B 3.0 2009
 6:   B 2.0 2010
 7:   B  NA 2011
 8:   C 3.0 2014
 9:   C 3.0 2019
10:   C 3.0 2020
11:   C 4.0 2021

期望的输出:

   grp  nr   yr nr_roll_period_3
1    A 1.0 2009               NA
2    A 2.0 2009               NA
3    A 1.5 2009               NA
4    A 1.0 2010               NA
5    B 3.0 2009               NA
6    B 2.0 2010               NA
7    B  NA 2011               NA
8    C 3.0 2014               NA
9    C 3.0 2019               NA
10   C 3.0 2020               NA
11   C 4.0 2021         3.333333

逻辑:

  • 我想计算长度为 k 的时间段(假设为 3)的滚动平均值,其中 3 包括当前月/年/日(按组)
  • 但是,如果没有连续 3 年/月/日,这不应该计算任何内容
  • 同样,只要在此期间计算的列中有 NA,则输出应为 NA。

目前我有这个功能:

calculate_rolling_window <-

  function(dt, date_col, calc_col, id, k) {

    require(data.table)

    return(setDT(dt)[
      , paste(calc_col, "roll_period", k, sep = "_") := 
        sapply(get(date_col), function(x) mean(get(calc_col)[between(get(date_col), x - k + 1, x)])),
      by = mget(id)])

  }

它适用于日期列中没有重复项的常规情况。但是,对于重复项,它会失败:

    grp  nr   yr nr_roll_period_3
 1:   A 1.0 2009         1.500000
 2:   A 2.0 2009         1.500000
 3:   A 1.5 2009         1.500000
 4:   A 1.0 2010         1.375000
 5:   B 3.0 2009               NA
 6:   B 2.0 2010               NA
 7:   B  NA 2011               NA
 8:   C 3.0 2014               NA
 9:   C 3.0 2019               NA
10:   C 3.0 2020               NA
11:   C 4.0 2021         3.333333

关于如何处理这个问题有什么想法吗?不需要专门的 data.table 方法。

最佳答案

这可以通过在非等连接中分组来解决,以在长度为 k 的滚动窗口上聚合,连续过滤 k年,以及一个更新连接:

library(data.table)
k <- 3L
# group by join parameters of a non-equi join
mDT <- setDT(DT)[.(grp = grp, upper = yr, lower = yr - k), 
                 on = .(grp, yr <= upper, yr > lower), 
                 .(uniqueN(x.yr), mean(nr)), by = .EACHI]
# update join with filtered intermediate result
DT[mDT[V1 == k], on = .(grp, yr), paste0("nr_roll_period_", k) := V2]
DT

返回 OP 的预期结果:

    grp  nr   yr nr_roll_period
 1:   A 1.0 2009             NA
 2:   A 2.0 2009             NA
 3:   A 1.5 2009             NA
 4:   A 1.0 2010             NA
 5:   B 3.0 2009             NA
 6:   B 2.0 2010             NA
 7:   B  NA 2011             NA
 8:   C 3.0 2014             NA
 9:   C 3.0 2019             NA
10:   C 3.0 2020             NA
11:   C 4.0 2021       3.333333

中间结果 mDT 包含 k 期间的滚动平均值 V2 和唯一/不同年份的计数 V1在每个时期内。它由 DT非等值连接创建,其中包含由 即时创建的上界和下界的 data.table。( grp = grp, upper = yr, lower = yr - k).

mDT
    grp   yr   yr V1       V2
 1:   A 2009 2006  1 1.500000
 2:   A 2009 2006  1 1.500000
 3:   A 2009 2006  1 1.500000
 4:   A 2010 2007  2 1.375000
 5:   B 2009 2006  1 3.000000
 6:   B 2010 2007  2 2.500000
 7:   B 2011 2008  3       NA
 8:   C 2014 2011  1 3.000000
 9:   C 2019 2016  1 3.000000
10:   C 2020 2017  2 3.000000
11:   C 2021 2018  3 3.333333

这是针对恰好包含 k distinct 年的行进行过滤的:

mDT[V1 == k]
   grp   yr   yr V1       V2
1:   B 2011 2008  3       NA
2:   C 2021 2018  3 3.333333

最后,它与 DT 结合以将新列附加到 DT

请注意,如果输入数据中有 NA,则 mean() 默认返回 NA

数据

library(data.table)
DT <- fread(text = "rn    grp  nr   yr
 1:   A 1.0 2009
 2:   A 2.0 2009
 3:   A 1.5 2009
 4:   A 1.0 2010
 5:   B 3.0 2009
 6:   B 2.0 2010
 7:   B  NA 2011
 8:   C 3.0 2014
 9:   C 3.0 2019
10:   C 3.0 2020
11:   C 4.0 2021", drop = 1L)

关于可以处理重复的不规则时间序列的滚动窗口函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52725965/

相关文章:

r - 如何在一行中为多个变量分配相同的值?

php - 使用 CodeIgniter 的 MySQL 查询问题

r - 如何针对多个输入运行脚本并根据输入名称保存结果对象?

r - 使用 tbats 预测每周数据

r - PCA - 主要成分是如何映射的?

r - 优化 R 中的嵌套 foreach dopar

r - 计算自加入R年以来的客户平均购买次数

ios - 显示应用程序首次打开的日期

java - 如何解析这个日期格式

python - pandas 时间戳和包含 timedelta 值的数组的总和