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

Мне нужно сложить значения, соответствующие определенному диапазону дат, и мне нужно сделать это для многих предметов.

В следующем примере df1 содержит даты начала и окончания трех предметов, а df2 содержит даты и их соответствующие значения:

df1<-data.frame(sub=c("a","b","c"), 
                start=as.Date(c("2015/10/13","2015/10/13","2015/10/11")), 
                end=as.Date(c("2015/10/16","2015/10/18","2015/10/15")))

df2<-data.frame(date=seq(as.Date("2015/10/11"), as.Date("2015/10/18"), "days"), 
                value=c(32,30,28,15,19,23,35,18))

> df1
  sub      start        end
1   a 2015-10-13 2015-10-16
2   b 2015-10-13 2015-10-18
3   c 2015-10-11 2015-10-15

> df2
        date value
1 2015-10-11    32
2 2015-10-12    30
3 2015-10-13    28
4 2015-10-14    15
5 2015-10-15    19
6 2015-10-16    23
7 2015-10-17    35
8 2015-10-18    18

Я хочу суммировать value в df2 с start даты до end даты в df1, и я хочу сделать это для каждого sub (в реальной задаче есть много предметов (т.е. пары начинающих и даты окончания), и поэтому я думаю, что я должен использовать цикл for).

Я ожидаю что-то вроде этого:

sub sum
a   85
b   138
c   124

, где a = 28 + 15 + 19 + 23, b = 28 + 15 + 19 + 23 + 35 + 18 и c = 32 + 30 + 28 + 15 + 19

Любая помощь приветствуется

Ответы [ 3 ]

1 голос
/ 22 мая 2019

Опция с mapply будет состоять в том, чтобы создать последовательность дат между start и end датами в df1 и установить подмножество этих дат из df2 и sum value.

df1$sum <- mapply(function(x, y) sum(df2$value[df2$date %in% x:y]), 
           df1$start, df1$end)


df1[c(1, 4)]
#  sub sum
#1   a  85
#2   b 138
#3   c 124
1 голос
/ 22 мая 2019

Параметр будет non-equi объединяться без использования петли

library(data.table)
setDT(df2)[df1,  .(sub = sub, sum = sum(value)), 
      on = .(date >= start, date <= end), by = .EACHI][, .(sub, sum)]
#    sub sum
#1:   a  85
#2:   b 138
#3:   c 124

или с использованием fuzzyjoin в tidy способе

library(fuzzyjoin)
library(dplyr)
fuzzy_left_join(df2, df1, by = c(date = 'start', date = 'end'), 
        match_fun = list(`>=`, `<=`)) %>% 
  group_by(sub) %>% 
  summarise(value = sum(value))
# A tibble: 3 x 2
#  sub   value
#  <fct> <dbl>
#1 a        85
#2 b       138
#3 c       124
0 голосов
/ 22 мая 2019

Это можно сделать одним оператором SQL, например:

library(sqldf)

sqldf("select a.sub, sum(b.value) as sum
  from df1 as a
  left join df2 as b on b.date between a.start and a.end
  group by a.sub")

дает:

  sub   sum
1   a    85
2   b   138
3   c   124
...