我有一个数据表,其中包含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实现此目的吗?
谢谢!
答案 0 :(得分:2)
使用tidyverse
和lubridate
,我们首先使用Date
将Date
转换为实际的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