代码之家  ›  专栏  ›  技术社区  ›  arg0naut91

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

  •  2
  • arg0naut91  · 技术社区  · 7 年前

        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)])
    
      }
    

    它适用于常规情况,其中date列中没有重复项。但是,对于副本,它会失败:

        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 接近。

    1 回复  |  直到 6 年前
        1
  •  6
  •   Community Mohan Dere    6 年前

    这可以通过 非等联接中的分组 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
    

        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 包含滚动平均值 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
    

    对于包含 不同的

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

    最后,这与 .

    请注意 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)