эффективно рассчитать годовую накопленную сумму - PullRequest
0 голосов
/ 10 января 2019

У меня есть набор данных с квартальными транзакциями. PERIOD представляет четверть транзакции, а INCREM представляет дополнительные суммы.

tbl <- data.frame(PERIOD = c(2,3,6,10,11),
                  INCREM = c(10,50,-30,-10,-20))

Я хочу получить годовые накопленные суммы (таким образом, накопленная сумма за периоды 4, 8, 12).

library(dplyr)
library(tidyr)

tbl %>%
  mutate(CUMSUM = cumsum(INCREM)) %>%
  select(-INCREM) %>%
  mutate(PERIOD = factor(PERIOD, 1:12)) %>%
  complete(PERIOD) %>%
  fill(CUMSUM) %>%
  mutate(PERIOD = as.numeric(PERIOD)) %>%
  filter(PERIOD %% 4 == 0)

Результат:

  PERIOD CUMSUM
1      4     60
2      8     30
3     12      0

Это работает, но не очень эффективно. Исходный набор данных состоит из 5 строк, а окончательный набор данных состоит из 3 строк, но в середине цепочки dplyr (после fill()) набор данных состоит из 12 строк.

Есть ли более эффективный способ получения годовых совокупных сумм?

Кроме того, мои фактические данные поступают из запроса к базе данных. Как вы думаете, было бы лучше для меня позаботиться об этом кумулятивном суммировании в SQL-запросе, прежде чем манипулировать в R?

Ответы [ 2 ]

0 голосов
/ 10 января 2019

вырезать, безусловно, путь. Вы также можете просто рассчитать совокупную сумму, а затем сохранить последние строки периода. Это позволяет избежать совокупного шага.

tbl$prd <- cut(tbl$PERIOD, c(1,4,8,Inf), labels=c(4,8,12))
tbl$cumsum <- cumsum(tbl$INCREM)
tbl[!duplicated(tbl$prd, fromLast=TRUE),c("prd","cumsum")]
#   prd cumsum
# 2   4     60
# 3   8     30
# 5  12      0
0 голосов
/ 10 января 2019

Как подсказал @thelatemail, вы можете использовать cut для создания групп, затем sum значения в каждой группе и, наконец, cumsum для всех значений.

library(dplyr)
tbl %>%
  group_by(quarter = cut(PERIOD, c(1,4,8,Inf), labels=c(4,8,12))) %>%
  summarise(CUMSUM = sum(INCREM)) %>%
  ungroup() %>%
  mutate(CUMSUM = cumsum(CUMSUM))

#  quarter CUMSUM
#  <fct>    <dbl>
#1   4       60
#2   8       30
#3  12        0

Используя ту же логику, слишком сложный подход base R для размещения в одной строке:

transform(aggregate(INCREM~PERIOD, 
  transform(tbl, PERIOD = cut(PERIOD, c(1,4,8,Inf), labels=c(4,8,12))), sum), 
    INCREM = cumsum(INCREM))


#  PERIOD INCREM
#1      4     60
#2      8     30
#3     12      0

что на самом деле означает

tbl$PERIOD <- cut(tbl$PERIOD, c(1,4,8,Inf), labels=c(4,8,12))
tbl1 <- aggregate(INCREM~PERIOD, tbl, sum)
tbl1$INCREM <- cumsum(tbl1$INCREM)
...