【问题标题】:R - Cumulative sum that crosses yearsR - 跨年的累积和
【发布时间】:2020-11-04 01:06:16
【问题描述】:

我有一个包含每日降水量测量值的数据表,如下所示:

library(data.table)
pr <- data.table(date=seq(as.Date("2000-01-01"), as.Date("2004-12-31"), by="1 day"),
                 precip=runif(1827, 0, 20))
            date    precip
   1: 2000-01-01  8.390553
   2: 2000-01-02 11.753791
   3: 2000-01-03  1.346553
   4: 2000-01-04 15.130108
   5: 2000-01-05  2.027514
  ---                     
1823: 2004-12-27 17.550784
1824: 2004-12-28  7.054898
1825: 2004-12-29  4.458190
1826: 2004-12-30  6.989788
1827: 2004-12-31  2.257400

我想获得此数据集中所有生长季节的累积降水量,其中生长季节定义为 9 月至 4 月之间的时间段。

因此,生成的数据表应包含 Sep2000 - Apr2001、Set2001 - Apr 2002 等的累积总和。

如何做到这一点?

【问题讨论】:

    标签: r data.table cumulative-sum


    【解决方案1】:

    这是data.table 方法。我们首先确定生长 (TRUE) / 收获 (FALSE) 季节,然后给每个季节一个 run-length id,最后总结开始和结束日期以及按季节计数的总降水量。

    set.seed(1)
    pr <- data.table(
      date=seq(as.Date("2000-01-01"), as.Date("2004-12-31"), by="1 day"),
      precip=runif(1827, 0, 20)
    )
    
    pr[
      , gr_season := !(month(date) %in% 5:8)
    ][
      , season_count := rleidv(gr_season) 
    ][
      gr_season == TRUE, .(period = paste0(head(date, 1L), "/", tail(date, 1L)), precip = sum(precip)), 
      by = season_count
    ]
    

    输出

       season_count                period   precip
    1:            1 2000-01-01/2000-04-30 1251.741
    2:            3 2000-09-01/2001-04-30 2352.559
    3:            5 2001-09-01/2002-04-30 2466.817
    4:            7 2002-09-01/2003-04-30 2326.178
    5:            9 2003-09-01/2004-04-30 2418.478
    6:           11 2004-09-01/2004-12-31 1136.972
    

    生长季节的每日 cumsum

    pr[
      , gr_season := !(month(date) %in% 5:8)
    ][
      , season_count := rleidv(gr_season)
    ][
      gr_season == TRUE, .(date = date, precip = cumsum(precip)), 
      by = season_count
    ]
    

    输出

          season_count       date      precip
       1:            1 2000-01-01    5.310173
       2:            1 2000-01-02   12.752651
       3:            1 2000-01-03   24.209719
       4:            1 2000-01-04   42.373874
       5:            1 2000-01-05   46.407513
      ---                                    
    1208:           11 2004-12-27 1101.280221
    1209:           11 2004-12-28 1112.926760
    1210:           11 2004-12-29 1114.345408
    1211:           11 2004-12-30 1125.758288
    1212:           11 2004-12-31 1136.971833
    

    【讨论】:

    • 我喜欢这个答案,因为它使用data.table。但是我不习惯rleidv。它不应该创建一个连续的season_count吗?
    • 是否可以显示“每日”累积值,而不是单个总值?
    • 是的,有可能。检查更新。 @thiagoveloso
    • rleidv 的工作方式如下:如果您有一个序列 TTTFFTTF,那么它将其编码为 11122334。每个条纹都有一个唯一的 id。
    【解决方案2】:

    4 月底距年初还有 120 天。如果您将date 列中的所有条目减去120 天以创建pseudodate 列,则您的生长期每天的pseudodate 将转移到上一年。由于从 9 月 1 日减去 120 天即为同一年的 5 月 4 日,因此 5 月 4 日之前的任何pseudodate 都将处于非生长期,并且在该日期或之后直到年底的任何内容都必须处于生长期那是从那年的九月开始的。通过这种方法,我们可以很容易地根据是否处于生长期,以及根据生长期开始的年份来标记每个实际日期。

    那么我们需要做的就是过滤掉不在生长期的日期,group_by生长期开始的那一年,并在precip列上执行cumsum

    library(dplyr)
    library(lubridate)
    
    pr %>% mutate(pseudodate = date - days(120),
                  is_growing = yday(pseudodate) > 125,
                  season_beginning = year(pseudodate)) %>%
      filter(is_growing) %>%
      mutate(cum_precip = cumsum(precip)) %>%
      select(date, precip, season_beginning, cum_precip)
    
    #>             date    precip season_beginning  cum_precip
    #>    1: 2000-01-01 17.694152             1999    17.69415
    #>    2: 2000-01-02  6.066319             1999    23.76047
    #>    3: 2000-01-03  4.793192             1999    28.55366
    #>    4: 2000-01-04 15.753112             1999    44.30678
    #>    5: 2000-01-05 12.253172             1999    56.55995
    #>   ---                                                  
    #> 1198: 2004-12-27  8.983804             2004 11490.72677
    #> 1199: 2004-12-28  6.740315             2004 11497.46709
    #> 1200: 2004-12-29  3.899960             2004 11501.36705
    #> 1201: 2004-12-30  6.357432             2004 11507.72448
    #> 1202: 2004-12-31  3.950666             2004 11511.67515
    

    当然,由于这个示例数据集从 1 月 1 日开始,我们已经错过了该季节几个月的生长期,因此如果第一年也从 1 月开始,则可能需要从您的实际数据中删除。

    【讨论】:

    • 我更喜欢这个答案,因为它提供了每日 cumsum,这是我需要绘制的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    • 2021-06-13
    • 2013-05-20
    • 2020-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多