【问题标题】:Cumulative sum from a month ago until the current day for all the rows所有行从一个月前到当天的累计总和
【发布时间】:2019-09-22 05:15:19
【问题描述】:

我有一个带有 ID、日期和值的 data.table,如下所示:

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 实现这一点吗?

谢谢!

【问题讨论】:

    标签: r date data.table cumsum


    【解决方案1】:

    这是另一个有效的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
    

    【讨论】:

      【解决方案2】:

      这主要是一个滚动求和的问题。 froll() 可能会起作用,但您必须先完成数据集,以便您可以说出向后滚动多少天。

      在这里我做了一个非 equi 自连接。由于data.table希望在join之前生成所有字段,所以我必须添加一个列Dates_Lower = Dates-30,这样我才能完成非等条件。我与last(Value) 的链使它工作,但我并不总是确定这些自加入...

      我还将 Date 转换为 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
      

      【讨论】:

        【解决方案3】:

        使用tidyverselubridate,我们首先使用as.DateDate 转换为实际的Date 对象,然后使用group_by ContractID 和每个Date sum @987654介于当前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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-05-09
          • 1970-01-01
          • 1970-01-01
          • 2020-05-09
          • 2017-03-25
          • 1970-01-01
          • 2012-09-22
          • 1970-01-01
          相关资源
          最近更新 更多