所有行从一个月前到当前日期的累计总和

时间:2019-05-03 16:04:36

标签: r date data.table cumsum

我有一个数据表,其中包含ID,日期和值,如下所示:

DT <- setDT(data.frame(ContractID= c(1,1,1,2,2), Date = c("2018-02-01", "2018-02-20", "2018-03-12", "2018-02-01", "2018-02-12"), Value = c(10,20,30,10,20)))

   ContractID       Date Value
1:          1 2018-02-01    10
2:          1 2018-02-20    20
3:          1 2018-03-12    30
4:          2 2018-02-01    10
5:          2 2018-02-12    20

我想要一个新列,其中包含一个月前到当日每一行的每个ID的累计总金额,如下表所示。 注意:第三行是第二行和自己的第三行的总和,因为2018-03-12减去1个月大于2018-02-01,所以我们在总和中不包括第一行。

   ContractID       Date Value Cum_Sum_1M
1:          1 2018-02-01    10         10
2:          1 2018-02-20    20         30
3:          1 2018-03-12    30         50
4:          2 2018-02-01    10         10
5:          2 2018-02-12    20         30

有什么方法可以使用data.table实现此目的吗?

谢谢!

3 个答案:

答案 0 :(得分:2)

使用tidyverselubridate,我们首先使用DateDate转换为实际的as.Date对象,然后使用group_by ContractID以及每个Date sum的{​​{1}},介于当前Value和当前Date前一个月之间。

Date

答案 1 :(得分:2)

这在很大程度上是一个滚动的问题。 froll()可能会起作用,但是您必须先完成数据集,以便可以说出要回滚多少天。

在这里,我进行非等额自我加入。由于data.table希望在连接之前生成所有字段,因此我必须添加一列Dates_Lower = Dates-30,以便可以完成非公平条件。我与last(Value)的链使其有效,但是我对这些自联接并不总是很确定...

我还将日期转换为as.Date,并将其重命名为Date()是基本函数。

library(data.table)

dt <- data.table(ContractID= c(1,1,1,2,2)
                 , Dates = as.Date(c("2018-02-01", "2018-02-20", "2018-03-12", "2018-02-01", "2018-02-12"))
                 , Value = c(10,20,30,10,20))

dt[dt[, .(ContractID, Dates, Dates_Lower = Dates - 30, Value)] #self-join
   ,on = .(ContractID = ContractID
          , Dates >= Dates_Lower
          , Dates <= Dates
          )
   , j = .(ContractID, Dates, Value)
   , allow.cartesian = TRUE
   ][, j = .(Value = last(Value), Cum_Sum_1M = sum(Value))
     ,by = .(ContractID, Dates)
   ]
   ContractID      Dates Value Cum_Sum_1M
1:          1 2018-02-01    10         10
2:          1 2018-02-20    20         30
3:          1 2018-03-12    30         50
4:          2 2018-02-01    10         10
5:          2 2018-02-12    20         30

答案 2 :(得分:0)

这是另一个有效的data.table解决方案。

dt[, Date := lubridate::ymd( Date ) ]
setkey(dt, Date)
dt[dt, Cum_Sum_1M := {
  val = dt[ ContractID == i.ContractID & Date %between% c( i.Date - months(1), i.Date ), Value];
  list( sum( val ) )
}, by = .EACHI ]
setkey(dt, ContractID, Date)

输出

#    ContractID       Date Value Cum_Sum_1M
# 1:          1 2018-02-01    10         10
# 2:          1 2018-02-20    20         30
# 3:          1 2018-03-12    30         50
# 4:          2 2018-02-01    10         10
# 5:          2 2018-02-12    20         30