【问题标题】:check whether value changed over time within group dplyr检查组 dplyr 中的值是否随时间变化
【发布时间】:2020-03-09 11:51:11
【问题描述】:

我的 df 看起来像:

# A tibble: 14 x 3
   user_id flag  order
     <dbl> <chr> <dbl>
 1       1 aaa       1
 2       1 aaa       2
 3       1 aaa       3
 4       1 bbb       4
 5       2 bbb       1
 6       2 bbb       2
 7       3 aaa       1
 8       3 aaa       2
 9       3 bbb       3
10       4 ccc       1
11       4 aaa       2
12       4 aaa       3
13       4 aaa       4
14       4 aaa       5



test_df <- tibble::tribble(
             ~user_id, ~flag, ~order,
                    1, "aaa",      1,
                    1, "aaa",      2,
                    1, "aaa",      3,
                    1, "bbb",      4,
                    2, "bbb",      1,
                    2, "bbb",      2,
                    3, "aaa",      1,
                    3, "aaa",      2,
                    3, "bbb",      3,
                    4, "ccc",      1,
                    4, "aaa",      2,
                    4, "aaa",      3,
                    4, "aaa",      4,
                    4, "aaa",      5)
  • user_id:每个用户的唯一标识符
  • 标志(字符串)
  • 订购

我想检查每个 user_id 的标志是否在订单中发生了变化。

我想创建一个列has_changedvalued:

  • has_changed 如果标志在 order 之后的某个时间点更改为 bbb,则值为 != 从 1 开始。

我做到了:

test_df %>%
  group_by(user_id) %>%
  mutate(has_changed = ifelse(any(flag == 'bbb' & order != 1), 'yes','no'))

导致:

# A tibble: 14 x 4
# Groups:   user_id [4]
   user_id flag  order has_changed
     <dbl> <chr> <dbl> <chr>      
 1       1 aaa       1 yes        
 2       1 aaa       2 yes        
 3       1 aaa       3 yes        
 4       1 bbb       4 yes        
 5       2 bbb       1 yes        
 6       2 bbb       2 yes        
 7       3 aaa       1 yes        
 8       3 aaa       2 yes        
 9       3 bbb       3 yes        
10       4 ccc       1 no         
11       4 aaa       2 no         
12       4 aaa       3 no         
13       4 aaa       4 no         
14       4 aaa       5 no    

给我一​​个错误的结果,因为 user_id == 2 没有改变,因为它一直有标志 bbb

我想要的输出应该是这样的:

# A tibble: 14 x 4
   user_id flag  order has_changed
     <dbl> <chr> <dbl> <chr>      
 1       1 aaa       1 yes        
 2       1 aaa       2 yes        
 3       1 aaa       3 yes        
 4       1 bbb       4 yes        
 5       2 bbb       1 no         
 6       2 bbb       2 no         
 7       3 aaa       1 yes        
 8       3 aaa       2 yes        
 9       3 bbb       3 yes        
10       4 ccc       1 no         
11       4 aaa       2 no         
12       4 aaa       3 no         
13       4 aaa       4 no         
14       4 aaa       5 no  

【问题讨论】:

    标签: r dplyr group-by tidyverse


    【解决方案1】:

    如果我理解你的问题,你想识别user_id,这样对于order == 1,你有flag != bbb,还有一些后续的order != 1flag == bbb

    如果我们把这个逻辑拼出来,我们写

    library(tidyverse)
    
    test_df %>%
      group_by(user_id) %>%
      mutate(first_bbb = any(flag != 'bbb' & order == 1),
             subsequent_not_bbb = any(flag == 'bbb' & order != 1),
             has_changed = if_else(first_bbb & subsequent_not_bbb, 'yes', 'no'))
    

    产生

    # A tibble: 14 x 6
    # Groups:   user_id [4]
       user_id flag  order first_bbb subsequent_not_bbb has_changed
         <dbl> <chr> <dbl> <lgl>     <lgl>              <chr>      
     1       1 aaa       1 TRUE      TRUE               yes        
     2       1 aaa       2 TRUE      TRUE               yes        
     3       1 aaa       3 TRUE      TRUE               yes        
     4       1 bbb       4 TRUE      TRUE               yes        
     5       2 bbb       1 FALSE     TRUE               no         
     6       2 bbb       2 FALSE     TRUE               no         
     7       3 aaa       1 TRUE      TRUE               yes        
     8       3 aaa       2 TRUE      TRUE               yes        
     9       3 bbb       3 TRUE      TRUE               yes        
    10       4 ccc       1 TRUE      FALSE              no         
    11       4 aaa       2 TRUE      FALSE              no         
    12       4 aaa       3 TRUE      FALSE              no         
    13       4 aaa       4 TRUE      FALSE              no         
    14       4 aaa       5 TRUE      FALSE              no         
    

    has_changed 列符合您想要的输出。您当然可以通过管道输入select(user_id, flag, order, has_changed) 以完全重现您想要的输出。或者,这里有一个更简洁(如果可能不太可读)的版本:

    library(tidyverse)
    
    test_df %>%
      group_by(user_id) %>%
      mutate(has_changed = if_else(any(flag != 'bbb' & order == 1) & any(flag == 'bbb' & order != 1), 'yes', 'no'))
    

    这给了

    # A tibble: 14 x 4
    # Groups:   user_id [4]
       user_id flag  order has_changed
         <dbl> <chr> <dbl> <chr>      
     1       1 aaa       1 yes        
     2       1 aaa       2 yes        
     3       1 aaa       3 yes        
     4       1 bbb       4 yes        
     5       2 bbb       1 no         
     6       2 bbb       2 no         
     7       3 aaa       1 yes        
     8       3 aaa       2 yes        
     9       3 bbb       3 yes        
    10       4 ccc       1 no         
    11       4 aaa       2 no         
    12       4 aaa       3 no         
    13       4 aaa       4 no         
    14       4 aaa       5 no  
    

    根据需要。

    【讨论】:

      【解决方案2】:

      对于user_id,如果any 值的flag 值为'bbb',而先前的值不是'bbb',则为组返回'yes',否则返回'no'

      library(dplyr)
      
      test_df %>%
        group_by(user_id) %>%
        mutate(has_changed = if(any(flag == 'bbb' & 
                               lag(flag) != 'bbb', na.rm = TRUE)) 'yes' else 'no') %>%
        ungroup
      
      #  user_id flag  order has_changed
      #     <dbl> <chr> <dbl> <chr>      
      # 1       1 aaa       1 yes        
      # 2       1 aaa       2 yes        
      # 3       1 aaa       3 yes        
      # 4       1 bbb       4 yes        
      # 5       2 bbb       1 no         
      # 6       2 bbb       2 no         
      # 7       3 aaa       1 yes        
      # 8       3 aaa       2 yes        
      # 9       3 bbb       3 yes        
      #10       4 ccc       1 no         
      #11       4 aaa       2 no         
      #12       4 aaa       3 no         
      #13       4 aaa       4 no         
      #14       4 aaa       5 no         
      

      【讨论】:

        猜你喜欢
        • 2021-02-28
        • 1970-01-01
        • 1970-01-01
        • 2021-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多