R - 产品过度轧制的总和 windows(四分之一)

R - Cumsum of product over rolling windows (quarters)

我想计算value列的累计和,有特殊要求。在一个季度(= 3 个月)过去后,value 会折旧一个常数,比如 0.9。这意味着,它现在仅将其原始值的 90% 计入 cumsum。当另一个季度过去时,重复此操作,即 90% 再次乘以常数 (0.9)(这等于原始值 * 0.9^2)。每经过一个季度,都会重复此过程,因此一年后原始值 运行 的 0.9^4 进入 cumsum,两年后 0.9^8,依此类推。完整的原始值仅在其日期变量之后的第一季度完全计入 cumsum。

示例:01/15 的值 100 将添加到 cumsum 100 直到 04/15,100*0.9=90 在 04/15 和 07/15 之间,100*0.9^2=81 在 07 月 15 日和 10 月 15 日之间,依此类推,请参阅 MRE 的 desired_output 列。

MRE:

df <- tribble(~date, ~value,~country,~desired_output,
              "2017-01-01", 2, "US", 2,
              "2017-01-05", 2, "UK", 8,
              "2017-01-05", 4, "US", 8,
              "2017-04-01", 5, "IT", 12.8,  # only the first observation is older than a quarter so calculate as (2*0.9+2+4+5)
              "2017-04-03", 3, "US", 115.8, #(2*0.9+2+4+5+3+100)
              "2017-04-03", 100, "US", 115.8,
              "2017-04-11", 20, "UK", 135.2,  # now the first three observations are older than a quarter (8*0.9+5+3+100+20)
              "2017-04-15", 6, "US", 141.2,
              "2017-07-02", 30, "US", 170.52,  # now the first observation is older than two quarters and the second, third, and forth observation are older than a quarter (2*0.9^2+11*0.9+3+100+20+6+30)
              "2017-10-12", 4, "UK", 151.912,  # ((2+2+4)*0.9^3+(5+3+100+20)*0.9^2+(6+30)*0.9+4+6)
              "2017-10-12", 6, "IT", 151.912) # (8*0.9^3+128*0.9^2+36*0.9+10)

假设常量值为 0.9,日期格式为 %Y-%b-%d.


进一步澄清问题的伪代码:

  1. 取每个 quarter/3 月的总和(从当前行的 date 开始)

  2. 根据这段时间到当前行日期的距离对常数求幂(例如,如果季度是从 今天)

  3. 将此调整后常数乘以相应季度(3 个月期间)的总和

  4. 取所有季度 cumsum 的 cumsum


在下一步中,我还想通过分组变量(例如 country)获取这个特定的 cumsum。

这里有一个选项:

DT[, do := 
    .SD[.SD, on=.(date<=date), by=.EACHI, {
        nqtr <- floor(pmax(0, i.date - x.date) / 90)
        sum(value * 0.9^nqtr)
    }]$V1
]

输出:

          date value country desired_output      do
 1: 2017-01-01     2      US          2.000   2.000
 2: 2017-01-05     2      UK          8.000   8.000
 3: 2017-01-05     4      US          8.000   8.000
 4: 2017-04-01     5      IT         12.800  12.800
 5: 2017-04-03     3      US        115.800 115.800
 6: 2017-04-03   100      US        115.800 115.800
 7: 2017-04-11    20      UK        135.200 135.200
 8: 2017-04-15     6      US        141.200 141.200
 9: 2017-07-02    30      US        170.520 160.220
10: 2017-10-12     4      UK        151.912 151.372
11: 2017-10-12     6      IT        151.912 151.372

区别在于我们如何定义季度。我用的是90d。如果3m真的很重要,我会更新post。例如,在 2017 年 7 月 2 日,使用 90 天时,第 2-6 行是 1 季度前,而在您的 OP 中,使用 3m 时只有第 2-4 行是 1 季度前。

数据:

library(data.table)    
DT <- fread('date,value,country,desired_output
"2017-01-01", 2, "US", 2
"2017-01-05", 2, "UK", 8
"2017-01-05", 4, "US", 8
"2017-04-01", 5, "IT", 12.8  
"2017-04-03", 3, "US", 115.8 
"2017-04-03", 100, "US", 115.8
"2017-04-11", 20, "UK", 135.2
"2017-04-15", 6, "US", 141.2
"2017-07-02", 30, "US", 170.52
"2017-10-12", 4, "UK", 151.912
"2017-10-12", 6, "IT", 151.912')
DT[, date := as.IDate(date, format="%Y-%m-%d")]

处理 3m 和国家要求:

DT[, do := 
    .SD[.SD, on=.(country, date<=date), by=.EACHI, {
        vec <- rev(seq(i.date, min(x.date)-93L, by="-1 quarter"))
        itvl <- findInterval(x.date, vec, rightmost.closed=TRUE)
        nqtr <- length(vec) - itvl - 1L
        sum(value * 0.9^nqtr)
    }]$V1
]

输出:

          date value country desired_output      do
 1: 2017-01-01     2      US          2.000   2.000
 2: 2017-01-05     2      UK          8.000   8.000
 3: 2017-01-05     4      US          8.000   8.000
 4: 2017-04-01     5      IT         12.800  13.000
 5: 2017-04-03     3      US        115.800 115.800
 6: 2017-04-03   100      US        115.800 115.800
 7: 2017-04-11    20      UK        135.200 135.200
 8: 2017-04-15     6      US        141.200 141.200
 9: 2017-07-02    30      US        170.520 170.520
10: 2017-10-12     4      UK        151.912 151.912
11: 2017-10-12     6      IT        151.912 151.912