【问题标题】:Create a group variable based on different criteria of consecutive scores根据连续分数的不同标准创建组变量
【发布时间】:2021-04-15 18:56:05
【问题描述】:

我有一个数据集,其中仅包含不同时间点的主题 ID 和分数。有没有办法让我根据他们的分数创建一个组变量?例如,如果一个科目有 6 个连续的 1 或 2 分,我会将它们放在“a”组 |如果他们连续4个3分,我会把他们放在“b”组|如果他们连续 6 次获得 4 分或更高的分数,我会将他们分到“c”组。

这是一个示例数据集:

id  score1  score2  score3  score4  score5  score6  score7  score8 group
101 2       2       2      2        1       2       2       1      a
102 4       4       3      3        3       3       4       4      b
103 4       5       5      5        5       6       5       5      c

这是上表没有“组”列的 R 代码

structure(list(id = c(101, 102, 103), score1 = c(2, 4, 4), score2 = c(2, 
4, 5), score3 = c(2, 3, 5), score4 = c(2, 3, 5), score5 = c(1, 
3, 5), score6 = c(2, 3, 6), score7 = c(2, 4, 5), score8 = c(1, 
4, 5)), row.names = c(NA, -3L), class = c("tbl_df", "tbl", "data.frame"
))

感谢任何想法!非常感谢:)

【问题讨论】:

    标签: r time count grouping


    【解决方案1】:

    所有解决方案的核心功能是rle()。你如何处理周围的一切都取决于你。

    library(tidyverse, quietly = TRUE)
    score_df %>% 
      pivot_longer(score1:score8) %>% 
      mutate(value = 
               case_when(
                 value <= 2 ~ 1,
                 value >= 4 ~ 4,
                 TRUE ~ value
               )) %>% 
      group_by(id) %>% 
      group_map(~{
        r <- rle(.$value)
        highest_val <- max(r$values)
        longest_len <- max(r$lengths)
        case_when(max(r$value) == 1 ~ "a",
                  any(r$lengths[which(r$value == 3)] >= 4) ~ "b",
                  any(r$lengths[which(r$value == 4)] >= 6) ~ "c",
                  TRUE ~ NA_character_)
      }) %>% 
      unlist()
    #> [1] "a" "b" "c"
    

    【讨论】:

      【解决方案2】:

      循环使用applyMARGIN = 1)的数据的数值列的行,将1到2的值替换为1,大于等于4的替换为4,然后得到@987654323 @ (run-length-encoding) 在行中的替换值上,提取“值”和“长度”,根据 OP 帖子中指定的条件创建逻辑表达式,如果满足这些条件,则返回所需的组值

      library(dplyr)
      df1$group <- apply(df1[-1], 1, function(x) {
           x <- case_when(x %in% 1:2 ~ 1, x >=4 ~ 4, TRUE ~ x)
           v1 <- rle(x)
           na.omit(case_when(v1$values == 1 & v1$lengths >= 6 ~  'a',
             v1$values == 3 & v1$lengths >=4 ~ 'b',
               v1$values ==4 & v1$lengths >= 6 ~  'c' )) })
      df1$group
      #[1] "a" "b" "c"
      

      或使用tidyverse

      library(data.table)
      library(tidyr)
      df1 %>%
         pivot_longer(cols = -id) %>% 
         mutate(newvalue = case_when(value %in% 1:2 ~ 1, 
               value >= 4 ~ 4, TRUE ~ value)) %>%
         add_count(id, grp = rleid(newvalue)) %>%
         group_by(id) %>%
         summarise( group = first(na.omit(case_when(newvalue == 1 & n >= 6 ~ 'a',
                 newvalue == 3 & n >= 4  ~'b',
                 newvalue == 4 & n >= 6 ~ 'c'))), .groups = 'drop') %>% 
        left_join(df1, .)
      

      -输出

      # A tibble: 3 x 10
      #     id score1 score2 score3 score4 score5 score6 score7 score8 group
      #  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl> <chr>
      #1   101      2      2      2      2      1      2      2      1 a    
      #2   102      4      4      3      3      3      3      4      4 b    
      #3   103      4      5      5      5      5      6      5      5 c    
      

      【讨论】:

        【解决方案3】:

        使用基础 R,您可以:

        pat <- c(a = "[12]{6}", b="3{4}", c="[4-9]{6}")
        
        cbind(df, group = names(pat)[max.col(sapply(pat, grepl, do.call(paste0, df[-1])))])
        
           id score1 score2 score3 score4 score5 score6 score7 score8 group
        1 101      2      2      2      2      1      2      2      1     a
        2 102      4      4      3      3      3      3      4      4     b
        3 103      4      5      5      5      5      6      5      5     c
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-01-21
          • 1970-01-01
          • 2022-08-04
          • 1970-01-01
          • 2011-07-10
          • 2021-09-22
          • 1970-01-01
          相关资源
          最近更新 更多