【问题标题】:R: lagged "cumulative" difference between two valuesR:两个值之间的滞后“累积”差异
【发布时间】:2021-12-22 12:30:21
【问题描述】:

我有一个包含许多组 (series) 的 data.frame df,其中数据 area 每年都会呈现。我正在尝试创建一个新列,其中diff 是第 1 行和第 2 行区域之间的差异。但我需要继续从“新”差异中减去。对于每个series,这需要按year 的降序完成。

df<-
structure(list(series = c("A218t23", "A218t23", "A218t23", "A218t23", 
"A218t23", "A218t23", "A218t23", "A218t23", "A218t23"), year = 2018:2010, 
    area = c(16409.3632611811, 274.5866082, 293.8540619, 323.0603775, 
    544.7366938, 108.0737561, 134.8579038, 143.14125, 167.8244576
    )), row.names = c(NA, -9L), groups = structure(list(series = "A218t23", 
    .rows = structure(list(1:9), ptype = integer(0), class = c("vctrs_list_of", 
    "vctrs_vctr", "list"))), row.names = c(NA, -1L), class = c("tbl_df", 
"tbl", "data.frame"), .drop = TRUE), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"))

我想要的输出如下所示:

因此,16409-275=16135 然后,16135-294=15841 等等。

我一直在使用的代码:

df_diffs <- df %>%
   dplyr::group_by(series) %>%
   dplyr::mutate(diff = area - dplyr::lag(area, default=0, order_by = desc(year)))

但是,这只是返回 area 列中的行之间的滞后差异。我正在寻找的结果是“累积”或运行差异。我已经查看了RcppRoll 和其他一些 SO 帖子,但没有运气。理想情况下,我可以将这一切都保存在一个管道框架内,因为我还有其他功能正在进行。如果有办法将第一行中的 NA 替换为当年对应的面积值,则可以加分。

非常感谢您的建议!

【问题讨论】:

    标签: r dplyr lag


    【解决方案1】:

    另一个选项,使用Reduce()

    
     df %>%
      group_by(series) %>%
      mutate(diff = Reduce("-", area, accumulate = T))
    
    # A tibble: 9 × 4
    # Groups:   series [1]
      series   year   area   diff
      <chr>   <int>  <dbl>  <dbl>
    1 A218t23  2018 16409. 16409.
    2 A218t23  2017   275. 16135.
    3 A218t23  2016   294. 15841.
    4 A218t23  2015   323. 15518.
    5 A218t23  2014   545. 14973.
    6 A218t23  2013   108. 14865.
    7 A218t23  2012   135. 14730.
    8 A218t23  2011   143. 14587.
    9 A218t23  2010   168. 14419.
    
    

    【讨论】:

    • 这很有魅力。我不知道Reduce,我期待更多地使用它。感谢其他人的建议,他们也工作了,但这个解决方案是最简单的。
    【解决方案2】:

    您可以通过调整累积和来实现。

    确实,您从每组的第一个值开始,然后减去之后的每个值。如果您认为第一个值之后的每个值都是负数,则累积总和将是您的预期输出。

    代码如下:

    library(tidyverse)
    df = df %>% 
      mutate(series="A") %>% 
      bind_rows(df)
    
    
    df %>% 
      group_by(series) %>% 
      mutate(
        x = ifelse(row_number()==1, area, -area),
        diff = cumsum(x)
      )
    #> # A tibble: 18 x 5
    #> # Groups:   series [2]
    #>    series   year   area      x   diff
    #>    <chr>   <int>  <dbl>  <dbl>  <dbl>
    #>  1 A        2018 16409. 16409. 16409.
    #>  2 A        2017   275.  -275. 16135.
    #>  3 A        2016   294.  -294. 15841.
    #>  4 A        2015   323.  -323. 15518.
    #>  5 A        2014   545.  -545. 14973.
    #>  6 A        2013   108.  -108. 14865.
    #>  7 A        2012   135.  -135. 14730.
    #>  8 A        2011   143.  -143. 14587.
    #>  9 A        2010   168.  -168. 14419.
    #> 10 A218t23  2018 16409. 16409. 16409.
    #> 11 A218t23  2017   275.  -275. 16135.
    #> 12 A218t23  2016   294.  -294. 15841.
    #> 13 A218t23  2015   323.  -323. 15518.
    #> 14 A218t23  2014   545.  -545. 14973.
    #> 15 A218t23  2013   108.  -108. 14865.
    #> 16 A218t23  2012   135.  -135. 14730.
    #> 17 A218t23  2011   143.  -143. 14587.
    #> 18 A218t23  2010   168.  -168. 14419.
    

    reprex package 创建于 2021-11-09 (v2.0.1)

    【讨论】:

      【解决方案3】:

      如果你在 tidyverse 中工作,你可以使用purrr::accumulate

      library(purrr)
      library(dplyr)
      
      df %>% 
        group_by(series) %>% 
        mutate(diff = accumulate(area, ~ .x - .y))
      

      在 purrr 函数中,.x 是当前值,.y 是之前的值。

      类似于Reduce 答案,您可以将算术运算符`-` 传递给它:accumulate(area, `-`)

      输出

      # A tibble: 9 x 4
      # Groups:   series [1]
        series   year   area   diff
        <chr>   <int>  <dbl>  <dbl>
      1 A218t23  2018 16409. 16409.
      2 A218t23  2017   275. 16135.
      3 A218t23  2016   294. 15841.
      4 A218t23  2015   323. 15518.
      5 A218t23  2014   545. 14973.
      6 A218t23  2013   108. 14865.
      7 A218t23  2012   135. 14730.
      8 A218t23  2011   143. 14587.
      9 A218t23  2010   168. 14419.
      

      【讨论】:

        【解决方案4】:

        改写this你可以做的回答:

        library(dplyr)
        
        df %>%
          dplyr::group_by(series) %>%
          dplyr::mutate(diff = c(area[1L], area[1L] - cumsum(area[-1L])))
        #> # A tibble: 9 × 4
        #> # Groups:   series [1]
        #>   series   year   area   diff
        #>   <chr>   <int>  <dbl>  <dbl>
        #> 1 A218t23  2018 16409. 16409.
        #> 2 A218t23  2017   275. 16135.
        #> 3 A218t23  2016   294. 15841.
        #> 4 A218t23  2015   323. 15518.
        #> 5 A218t23  2014   545. 14973.
        #> 6 A218t23  2013   108. 14865.
        #> 7 A218t23  2012   135. 14730.
        #> 8 A218t23  2011   143. 14587.
        #> 9 A218t23  2010   168. 14419.
        

        【讨论】:

          猜你喜欢
          • 2022-10-02
          • 2017-05-15
          • 2020-08-27
          • 2022-07-24
          • 2016-03-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-12
          相关资源
          最近更新 更多