【问题标题】:Count length of sequential consequtive values per group in R计算 R 中每组连续连续值的长度
【发布时间】:2021-05-08 21:02:45
【问题描述】:

我有一个带有结果值的数据集,我想知道每个长度出现的次数。 更具体地说,我想找出有多少 id 的序列从 1:2、1:3、1:4 等开始运行。 只有从 1 开始的序列是有意义的。

在这个例子中,id1 有一个从 1:3 开始的“完整”序列(因为数字 4 缺失),id2 有一个从 1:5 开始的序列,id3 有一个从 1:6 开始的序列,id4不计算在内,因为它不是以值 1 开始的,并且 id 5 的序列从 1:3 开始运行。

所以我们最终得到两个序列,直到 3,一个到 5,一个到 6。

有没有一种巧妙的方法来计算这个,而无需使用低效的循环?

示例数据:

data <- data.table( id    = c(1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4,5,5,5,5),
                    value = c(1,2,3,5,1,2,3,4,5,10,11,1,2,3,4,5,6,2,3,4,5,6,7,8,1,2,3,7))

 > data
    id value
 1:  1     1
 2:  1     2
 3:  1     3
 4:  1     5
 5:  2     1
 6:  2     2
 7:  2     3
 8:  2     4
 9:  2     5
10:  2    10
11:  2    11
12:  3     1
13:  3     2
14:  3     3
15:  3     4
16:  3     5
17:  3     6
18:  4     2
19:  4     3
20:  4     4
21:  4     5
22:  4     6
23:  4     7
24:  4     8
25:  5     1
26:  5     2
27:  5     3
28:  5     7
    id value

【问题讨论】:

    标签: r count data.table grouping


    【解决方案1】:
    out <- data[, len0 := rleid(c(TRUE, diff(value) == 1L)), by = .(id) ][
      , .(value1 = first(value), len = .N), by = .(id, len0) ]
    out
    #       id  len0 value1   len
    #    <num> <int>  <num> <int>
    # 1:     1     1      1     3
    # 2:     1     2      5     1
    # 3:     2     1      1     5
    # 4:     2     2     10     1
    # 5:     2     3     11     1
    # 6:     3     1      1     6
    # 7:     4     1      2     7
    # 8:     5     1      1     3
    # 9:     5     2      7     1
    

    演练:

    • 在每个 id 中,都会创建 len0 以识别增加 1 的步骤
    • id,len0 内,使用第一个值(如果您只想要以1 开头的值,请参见下文)和运行的length 进行汇总

    如果你只想知道那些序列从一个开始的,过滤value1

    out[ value1 == 1L, ]
    #       id  len0 value1   len
    #    <num> <int>  <num> <int>
    # 1:     1     1      1     3
    # 2:     2     1      1     5
    # 3:     3     1      1     6
    # 4:     5     1      1     3
    

    (我认为此时您只需要idlen。)

    【讨论】:

      【解决方案2】:

      这是另一种选择:

      data[rowid(id)==value, max(value), id]
      

      输出:

         id V1
      1:  1  3
      2:  2  5
      3:  3  6
      4:  5  3
      

      【讨论】:

      • 太棒了!我认为在考虑这一点时我的条件太保守了;即序列不一定严格增加。因此,我也尝试检测以 1 开头的“尾随”序列(例如 d = data.table(id = 1, value = c(2:3, 1:3)))...干杯
      【解决方案3】:
      library(data.table)
      dt <- data.table( id    = c(1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4,5,5,5,5),
                          value = c(1,2,3,5,1,2,3,4,5,10,11,1,2,3,4,5,6,2,3,4,5,6,7,8,1,2,3,7))
      
      dt[, n := seq_len(.N) - value, by = id]
      res <- dt[n == 0, .SD[value == max(value)], by = id][, n := NULL]
      head(res)
      #>    id value
      #> 1:  1     3
      #> 2:  2     5
      #> 3:  3     6
      #> 4:  5     3
      

      reprex package (v1.0.0) 于 2021-02-04 创建

      【讨论】:

        【解决方案4】:

        使用dplyr 的一个选项可能是:

        data %>%
         group_by(id) %>%
         mutate(rleid = with(rle(c(0, diff(value)) <= 1), rep(seq_along(values), lengths))) %>%
         filter(rleid == 1 & min(value) == 1) %>%
         summarise(value = paste(value, collapse = "")) %>%
         group_by(value) %>%
         summarise(n = n(),
                   ids = toString(id))
        
          value      n ids  
          <chr>  <int> <chr>
        1 123        2 1, 5 
        2 12345      1 2    
        3 123456     1 3    
        

        【讨论】:

        • 我已经在基本 R 和 dplyr 中多次使用了 rle 单线,因为当我没有可靠地加载 data.table 时,它的 rleid 。我有点惊讶 tidyverse 中没有类似物,tbh,因为它的效用相当高。
        • @r2evans 完全同意,dplyr/tidyr 相当于 data.table::rleid() 将非常方便!另一方面,我想我看过tidyverse的创建者讨论过,如果我没记错的话,他们说他们不打算实现这样的功能。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-11-17
        • 2019-05-09
        • 1970-01-01
        • 2021-12-29
        • 1970-01-01
        • 2015-06-20
        • 1970-01-01
        相关资源
        最近更新 更多