【问题标题】:How to make an accumulated sum with constraints如何在约束条件下进行累加
【发布时间】:2019-05-22 15:20:16
【问题描述】:

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

在下一个示例中,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 中的 valuestart 日期到 df1 中的 enddate 求和,并且我想为每个 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

感谢任何帮助

【问题讨论】:

    标签: r dataframe for-loop constraints cumsum


    【解决方案1】:

    mapply 的一个选项是在df1 中创建一个介于startend 日期之间的日期序列,并将这些日期从df2sum 中设置为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
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        这可以在一条 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
        

        【讨论】:

          猜你喜欢
          • 2014-06-26
          • 1970-01-01
          • 2012-06-16
          • 1970-01-01
          • 1970-01-01
          • 2017-12-05
          • 1970-01-01
          • 2016-08-10
          • 1970-01-01
          相关资源
          最近更新 更多