Суммарная сумма за месяц до текущего дня по всем строкам - PullRequest
0 голосов
/ 03 мая 2019

У меня есть 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

Я хотел бы получить новый столбец с общей совокупной суммой для идентификатора с месяца назад дотекущий день для каждой строки, как в таблице ниже.NB: третья строка является суммой второй и собственной третьей, потому что 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 ]

2 голосов
/ 04 мая 2019

Это в значительной степени вопрос скользящей суммы.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 голосов
/ 04 мая 2019

Используя tidyverse и lubridate, мы сначала конвертируем Date в фактический Date объект, используя as.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
0 голосов
/ 07 мая 2019

Это другое рабочее решение 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
...