【问题标题】:Create dummy variable for student with All As OR As and Bs in R (Tidyverse)在 R (Tidyverse) 中使用 All As OR As 和 Bs 为学生创建虚拟变量
【发布时间】:2021-07-17 02:55:34
【问题描述】:

下午好,

我需要创建一个本学期所有 As 的学生列表。我需要创建另一个本学期所有 B 的学生列表。我无法弄清楚如何使用我拥有的数据来实际完成这项工作。以下是我拥有的和正在寻找的。有什么想法吗?

original_df <- 
  tribble(~id, ~subject, ~grade,
          "001", "ela", "A+",
          "001", "math", "A",
          "001", "science", "A-",
          "002", "ela", "A",
          "002", "math", "B+",
          "002", "science", "B-",
          "003", "ela", "A",
          "003", "math", "A",
          "003", "science", "A-",
          "004", "ela", "C",
          "004", "math", "C",
          "004", "science", "A+",
          )

summarized_df <- 
  tribble(~id, ~all_As, ~As_and_Bs,
          "001", 1, 0, 
          "002", 0, 1, 
          "003", 1, 0,
          "004", 0, 0
          )

【问题讨论】:

    标签: r tidyverse


    【解决方案1】:

    一种方法是在按“id”分组后,使用正则表达式检查“A”,或通过删除标点提取字母并检查“A”、“B”的all 是否存在

    library(dplyr)
    library(stringr)
    original_df %>%
       group_by(id) %>% 
       summarise(all_As = +(all(str_detect(grade, 'A'))),
         As_and_Bs = +(all(c('A', 'B') %in% str_remove(grade, '[-+]'))),
            .groups = 'drop')
    

    -输出

    # A tibble: 4 x 3
    #  id    all_As As_and_Bs
    #* <chr>  <int>     <int>
    #1 001        1         0
    #2 002        0         1
    #3 003        1         0
    #4 004        0         0
    

    或者像 cmets 中提到的 @BenBolker

    original_df %>%
       group_by(id) %>% 
       summarise(all_As=all(grepl("^A",grade)),
                 As_and_Bs=!all_As && all(grepl("^[AB]",grade)))
    

    【讨论】:

    • 我打算用all(grepl("^[AB]",grade))(或者用str_detect代替grepl和args的倒序)
    • 可能要注意+as.numeric() 的简写...
    • @BenBolker 如果所有 'A' 都是 TRUE 而没有任何 B,那这也不是 TRUE。我的意思是,如果你将它用于 As 和 Bs
    • summarise 是否按顺序工作?我们可以all_As=all(grepl("^A",grade)), As_and_Bs=!all_As &amp;&amp; all(grepl("^[AB],grade)) 吗?
    • @Mishalb 它是summarise 中的参数。在某些版本中,如果未提供,则会发出警告。默认情况下,它会按该顺序删除最后一个分组变量。您也可以查看here
    【解决方案2】:

    data.table 选项

    setDT(original_df)[
      ,
      .(
        all_As = +!var(startsWith(grade, "A")),
        As_and_Bs = +all(c("A", "B") %in% substr(grade, 1, 1))
      ), id
    ]
    

    给予

        id all_As As_and_Bs
    1: 001      1         0
    2: 002      0         1
    3: 003      1         0
    4: 004      0         0
    

    【讨论】:

      【解决方案3】:

      另一个data.table选项,尽量将函数和输入分开,使其灵活。

      library(data.table)
      setDT(original_df)
      
      only <- function(x,y) all(x == y)
      incl <- function(x,y) all(x %in% y)
      
      original_df[
        , 
        Map(
          function(l,f) f(l, substr(grade, 1, 1)),
          list(all_as = "A", all_bs = "B", as_and_bs = c("A","B")),
          c(only, only, incl)
        ),
        by=id
      ]
      
      #    id all_as all_bs as_and_bs
      #1: 001   TRUE  FALSE     FALSE
      #2: 002  FALSE  FALSE      TRUE
      #3: 003   TRUE  FALSE     FALSE
      #4: 004  FALSE  FALSE     FALSE
      

      tidyverse 翻译:

      original_df %>%
        group_by(id) %>%
        mutate(subgrade = substr(grade,1,1)) %>%
        summarise(
          across(
            c(subgrade),
            list(
              all_as    = ~only(x="A", y=.x),
              all_bs    = ~only(x="B", y=.x),
              as_and_bs = ~incl(x=c("A","B"), y=.x)
            ),
            .names="{fn}"
          )
        )
      
      #`summarise()` ungrouping output (override with `.groups` argument)
      ## A tibble: 4 x 4
      #  id    all_as all_bs as_and_bs
      #  <chr> <lgl>  <lgl>  <lgl>    
      #1 001   TRUE   FALSE  FALSE    
      #2 002   FALSE  FALSE  TRUE     
      #3 003   TRUE   FALSE  FALSE    
      #4 004   FALSE  FALSE  FALSE 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-18
        • 2023-03-24
        • 2019-11-09
        • 2013-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多