所有行从一个月前到当天的累计总和
Cumulative sum from a month ago until the current day for all the rows
我有一个 data.table,其 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 的总累计总和,如下面的 table 所示。
注意:第三行是第二行和第三行的和,因为2018-03-12减去1个月大于2018-02-01,所以我们在cum sum中排除了第一行。
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 来实现吗?
谢谢!
使用 tidyverse
和 lubridate
,我们首先使用 as.Date
将 Date
转换为实际的 Date
对象,然后 group_by
ContractID
并且对于每个 Date
sum
Value
介于当前 Date
和当前 Date
.
之前一个月
library(tidyverse)
library(lubridate)
DT %>%
mutate(Date = as.Date(Date)) %>%
group_by(ContractID) %>%
mutate(Cum_Sum_1M = map_dbl(1:n(), ~ sum(Value[(Date >= (Date[.] - months(1))) &
(Date <= Date[.])], na.rm = TRUE)))
# A tibble: 5 x 4
# Groups: ContractID [2]
# ContractID Date Value Cum_Sum_1M
# <dbl> <date> <dbl> <dbl>
#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
这主要是一道滚动求和题。 froll()
可能会起作用,但您必须先完成数据集,以便您可以说出要倒退多少天。
这里我做一个非equi自连接。由于 data.table 想要在连接之前生成所有字段,我必须添加一列 Dates_Lower = Dates-30
以便我可以完成非 equi 条件。我与 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
这是另一个有效的 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
我有一个 data.table,其 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 的总累计总和,如下面的 table 所示。 注意:第三行是第二行和第三行的和,因为2018-03-12减去1个月大于2018-02-01,所以我们在cum sum中排除了第一行。
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 来实现吗?
谢谢!
使用 tidyverse
和 lubridate
,我们首先使用 as.Date
将 Date
转换为实际的 Date
对象,然后 group_by
ContractID
并且对于每个 Date
sum
Value
介于当前 Date
和当前 Date
.
library(tidyverse)
library(lubridate)
DT %>%
mutate(Date = as.Date(Date)) %>%
group_by(ContractID) %>%
mutate(Cum_Sum_1M = map_dbl(1:n(), ~ sum(Value[(Date >= (Date[.] - months(1))) &
(Date <= Date[.])], na.rm = TRUE)))
# A tibble: 5 x 4
# Groups: ContractID [2]
# ContractID Date Value Cum_Sum_1M
# <dbl> <date> <dbl> <dbl>
#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
这主要是一道滚动求和题。 froll()
可能会起作用,但您必须先完成数据集,以便您可以说出要倒退多少天。
这里我做一个非equi自连接。由于 data.table 想要在连接之前生成所有字段,我必须添加一列 Dates_Lower = Dates-30
以便我可以完成非 equi 条件。我与 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
这是另一个有效的 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