如何在约束条件下进行累加

How to make an accumulated sum with constraints

我需要对特定日期范围内的值求和,我需要对很多科目执行此操作。

在下一个示例中,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

我想在 df2 中从 start 日期到 enddate 在 df1 中对 value 求和,我想对每个 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

感谢任何帮助

一个选项是 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

或者以tidy的方式使用fuzzyjoin

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

mapply 的一个选项是在 df1 中的 startend 之间创建一个日期序列,并从 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

这可以在单个 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