【问题标题】:R: How to start a new sub_id each time a new sequence beginsR:每次新序列开始时如何开始一个新的 sub_id
【发布时间】:2021-08-17 10:18:53
【问题描述】:

假设我有如下数据:

tibble(
    A = c(1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5),
    B = c(1, 1, 2, 1, 2, 3, 1, 2, 1, 1, 1, 2, 3, 4, 1, 1),
)

即,

# A tibble: 16 x 2
       A     B
   <dbl> <dbl>
 1     1     1
 2     2     1
 3     2     2
 4     2     1
 5     2     2
 6     2     3
 7     3     1
 8     3     2
 9     3     1
10     3     1
11     4     1
12     4     2
13     4     3
14     4     4
15     4     1
16     5     1

每次在由变量 A 定义的组内开始一个新序列时,我如何创建一个 sub_id,即,

tibble(
    A = c(1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5),
    B = c(1, 1, 2, 1, 2, 3, 1, 2, 1, 1, 1, 2, 3, 4, 1, 1),
    sub_id = c(1, 1, 1, 2, 2, 2, 1, 1, 2, 3, 1, 1, 1, 1, 2, 1)
)
# A tibble: 16 x 3
       A     B sub_id
   <dbl> <dbl>  <dbl>
 1     1     1      1
 2     2     1      1
 3     2     2      1
 4     2     1      2
 5     2     2      2
 6     2     3      2
 7     3     1      1
 8     3     2      1
 9     3     1      2
10     3     1      3
11     4     1      1
12     4     2      1
13     4     3      1
14     4     4      1
15     4     1      2
16     5     1      1

希望这是明确的定义。我想我是在对 row_number 进行某种逆操作

提前致谢,

詹姆斯。

【问题讨论】:

    标签: r group-by sequence rowid


    【解决方案1】:

    data.table 选项

    > setDT(df)[, sub_id := cumsum(B == 1), A][]
        A B sub_id
     1: 1 1      1
     2: 2 1      1
     3: 2 2      1
     4: 2 1      2
     5: 2 2      2
     6: 2 3      2
     7: 3 1      1
     8: 3 2      1
     9: 3 1      2
    10: 3 1      3
    11: 4 1      1
    12: 4 2      1
    13: 4 3      1
    14: 4 4      1
    15: 4 1      2
    16: 5 1      1
    

    【讨论】:

      【解决方案2】:

      使用base R

      df$sub_id <- with(df, ave(B ==1, A, FUN = cumsum))
      

      【讨论】:

      • 非常整洁。谢谢你。没想到 base 这么灵活。
      【解决方案3】:

      我们可以使用group_bycumsum

      library(dplyr)
      
      df %>%
        group_by(A) %>%
        mutate(sub_id = cumsum(B==1)
      

      输出:

      # Groups:   A [5]
             A     B sub_id
         <dbl> <dbl>  <int>
       1     1     1      1
       2     2     1      1
       3     2     2      1
       4     2     1      2
       5     2     2      2
       6     2     3      2
       7     3     1      1
       8     3     2      1
       9     3     1      2
      10     3     1      3
      11     4     1      1
      12     4     2      1
      13     4     3      1
      14     4     4      1
      15     4     1      2
      16     5     1      1
      

      【讨论】:

        【解决方案4】:

        你已经准备好了“配料”。

        (i) 对于每组 A 列 (ii) 检查是否有新的序列开始

        以下内容基于{dplyr}。出于演示目的,我创建了一个附加列/变量来显示“开始条件”。您可以将其合并为一个调用。

        我使用 TRUE/FALSE 的总和将 TRUE 编码为 1 的事实。如果这对您来说不明显,您可以使用 as.numeric(B == 1)

        library(dplyr)
        library(tibble)
        
        # load example data
        df <- tibble(
            A = c(1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5),
            B = c(1, 1, 2, 1, 2, 3, 1, 2, 1, 1, 1, 2, 3, 4, 1, 1),
            sub_id = c(1, 1, 1, 2, 2, 2, 1, 1, 2, 3, 1, 1, 1, 1, 2, 1)
        )
        
        # perform group-wise operations 
        df %>% 
           group_by(A) %>% 
        
           mutate(
        # --------------- highlight start of new sequence --------------
              start = B == 1
        # --------------- create cumsum over TRUEs----------------------
            , sub_id2 = cumsum(start)
        )
        

        这会产生您所寻找的:

        # A tibble: 16 x 5
        # Groups:   A [5]
               A     B sub_id start sub_id2
           <dbl> <dbl>  <dbl> <lgl>   <int>
         1     1     1      1 TRUE        1
         2     2     1      1 TRUE        1
         3     2     2      1 FALSE       1
         4     2     1      2 TRUE        2
         5     2     2      2 FALSE       2
         6     2     3      2 FALSE       2
         7     3     1      1 TRUE        1
         8     3     2      1 FALSE       1
         9     3     1      2 TRUE        2
        10     3     1      3 TRUE        3
        11     4     1      1 TRUE        1
        12     4     2      1 FALSE       1
        13     4     3      1 FALSE       1
        14     4     4      1 FALSE       1
        15     4     1      2 TRUE        2
        16     5     1      1 TRUE        1
        

        【讨论】:

        • 太棒了!我没有意识到你可以用 mutate 做到这一点(在 group_by 之后)。谢谢!
        猜你喜欢
        • 2021-10-03
        • 1970-01-01
        • 1970-01-01
        • 2021-07-19
        • 2018-07-06
        • 2016-01-12
        • 1970-01-01
        • 1970-01-01
        • 2014-10-31
        相关资源
        最近更新 更多