【问题标题】:Count consecutive month present in the data frame, by group按组计算数据框中存在的连续月份
【发布时间】:2021-05-02 00:10:59
【问题描述】:

在 R 中,我需要按组计算存在多少连续月份,直到该行的月份。这是一个运行计数,应在缺少月份后重新开始。这是一个示例,结果列中包含所需的结果。

date <- c("2020-01-01", "2020-02-01", "2020-03-01", "2020-05-01", "2020-06-01", "2020-01-01", "2020-03-01", "2020-04-01")
group <- c("a","a","a","a","a","b","b","b")
result <- c(1,2,3,1,2,1,1,2)

data.frame(date=as.Date(date), group=group, result=result)

对于组“a”,计数中断并从 5 月重新开始,因为“a”不存在 4 月。与“b”相同,2 月不存在,因此从 3 月重新开始计数。如何获取结果列?

【问题讨论】:

    标签: r


    【解决方案1】:

    这是一个data.table 选项,使用rowid + cumsum

    setDT(df)[, result := rowid(cumsum(c(TRUE, round(diff(date) / 30.42) != 1))), group]
    

    给了

             date group result
    1: 2020-01-01     a      1
    2: 2020-02-01     a      2
    3: 2020-03-01     a      3
    4: 2020-05-01     a      1
    5: 2020-06-01     a      2
    6: 2020-01-01     b      1
    7: 2020-03-01     b      1
    8: 2020-04-01     b      2
    

    数据

    > dput(df)
    structure(list(date = structure(c(18262, 18293, 18322, 18383,
    18414, 18262, 18322, 18353), class = "Date"), group = c("a",
    "a", "a", "a", "a", "b", "b", "b")), class = "data.frame", row.names = c(NA,
    -8L))
    

    【讨论】:

      【解决方案2】:

      我一直想提出一个 tidyverse 解决方案,但我无法解决计数器索引,因此我求助于编写自定义函数。这并不像@ThomasIsCoding 先生提出的解决方案那样有效,但我认为这将是对答案的一个不错的补充:

      library(dplyr)
      
      # First I write a custom function that does the counting based on your desired condition
      
      set_index <- function(x) {
        result <- vector("numeric", length(x))
        result[[1]] <- 1
      
        for(i in 2:length(x)) {
          if(x[[i]] - x[[i-1]] == 1) {
            result[[i]] <- result[[i-1]] + 1
          } else {
            result[[i]] <- 1
          }
        }
        result
      }
      
      # Then I applied it to the month column I extracted out of dates
      
      df %>% 
        mutate(month = month(date), 
               result = set_index(month)) %>%
        select(-month)
      
              date group result
      1 2020-01-01     a      1
      2 2020-02-01     a      2
      3 2020-03-01     a      3
      4 2020-05-01     a      1
      5 2020-06-01     a      2
      6 2020-01-01     b      1
      7 2020-03-01     b      1
      8 2020-04-01     b      2
      

      【讨论】:

        【解决方案3】:

        这是dplyr 方法:

        library(dplyr)
        
        df %>%
          mutate(date = as.Date(date)) %>%
          group_by(group, grp = cumsum(date - lag(date, default = as.Date('1900-01-01')) > 35)) %>%
          mutate(result2 = row_number()) %>%
          ungroup %>%
          select(-grp)
        
        #   date       group result result2
        #  <date>     <chr>  <dbl>   <int>
        #1 2020-01-01 a          1       1
        #2 2020-02-01 a          2       2
        #3 2020-03-01 a          3       3
        #4 2020-05-01 a          1       1
        #5 2020-06-01 a          2       2
        #6 2020-01-01 b          1       1
        #7 2020-03-01 b          1       1
        #8 2020-04-01 b          2       2
        

        我使用lag 中的默认日期作为as.Date('1900-01-01') 假设您的所有日期都大于该日期。我正在检查当前日期和前一个日期之间的天数是否大于 35,这是一个任意数字,只是为了确保差异超过一个月。

        【讨论】:

          【解决方案4】:

          将日期从 zoo 转换为 yearmon 类并将其乘以 12,以便连续的月份在内部是连续的整数。然后使用 seqid from collapse 生成一个分组变量,并在组内使用 1:n() 对它们进行排序。

          library(collapse)
          library(dplyr)
          library(zoo)
          
          DF %>% 
            group_by(group, result = seqid(12 * as.yearmon(date))) %>%
            mutate(result = 1:n()) %>%
            ungroup
          

          这可以在没有 dplyr 的情况下完成,如下所示:

          nr <- nrow(DF)
          tfm(DF, result = ave(1:nr, group, seqid(12*as.yearmon(date)), FUN = seq_along))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-03-29
            • 2020-05-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-05-18
            • 2021-12-26
            • 2020-01-25
            相关资源
            最近更新 更多