【问题标题】:Use group_by and case_when to produce single value per group使用 group_by 和 case_when 为每个组生成单个值
【发布时间】:2020-03-24 14:26:10
【问题描述】:

我有一个带有id 和stage 的data.frame。 stage 是字符,但对应于有序进程(A -> B -> C -> ...)。

expand.grid(id=c(1:5), stage = LETTERS[1:4]) %>%
 arrange(id) %>%
 mutate(flag = case_when(str_detect(stage, "D") ~ "Dance",
                         str_detect(stage, "C") ~ "Climb",
                         str_detect(stage, "B") ~ "Biceps",
                         str_detect(stage, "A") ~ "Aerobic"))

这会产生我所期望的,一个向量化的case by case标志列。但我想要的是我的case_when 的输出对于整个id 组是唯一的。所以我尝试添加group_by(id)

expand.grid(id=c(1:5), stage = LETTERS[1:4]) %>%
 arrange(id) %>%
 group_by(id) %>%
 mutate(flag = case_when(str_detect(stage, "D") ~ "Dance",
                         str_detect(stage, "C") ~ "Climb",
                         str_detect(stage, "B") ~ "Biceps",
                         str_detect(stage, "A") ~ "Aerobic"))

但这不会改变结果的性质。将mutate 更改为summarize 也不会产生我希望的“总结”效果。 我可能不完全理解 case_when() 和 group_by() 的功能,因此我无法编写正确的命令来获取我正在寻找的摘要。

我的预期输出应该有id,stage 是顺序中的最后一个阶段,flag 根据那个阶段。

     id stage flag 
  <int> <fct> <chr>
1     1 D     Dance
2     2 D     Dance
3     3 D     Dance
4     4 D     Dance
5     5 D     Dance

为了更清楚,我们假设id 1 和 2 在阶段 A,3 在 B,4 在 C,5 在 D。

toy <- expand.grid(id=c(1:5), stage = LETTERS[1:4]) %>%
 arrange(id) %>%
 group_by(id) %>%
 mutate(flag = case_when(str_detect(stage, "D") ~ "Dance",
                         str_detect(stage, "C") ~ "Climb",
                         str_detect(stage, "B") ~ "Biceps",
                         str_detect(stage, "A") ~ "Aerobic"))
# grabbing only some of them
toy <- toy[c(1, 5, 10, 15, 20),]

输出应如下所示:

     id stage flag   
  <int> <fct> <chr>  
1     1 A     Aerobic
2     2 A     Aerobic
3     3 B     Biceps 
4     4 C     Climb  
5     5 D     Dance

我可以重复id,我可以从那里总结一下。

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    您可以使用any(以及case_when 中的操作顺序在summarize 中获取您想要的flag。我们需要添加一点以保留stage。

    expand.grid(id=c(1:5), stage = LETTERS[1:4]) %>%
      arrange(id) %>%
      group_by(id) %>%
      summarize(
       stage = intersect(c("D","C","B","A"), stage)[1],
       flag = case_when(any(str_detect(stage, "D")) ~ "Dance",
                        any(str_detect(stage, "C")) ~ "Climb",
                        any(str_detect(stage, "B")) ~ "Biceps",
                        any(str_detect(stage, "A")) ~ "Aerobic")
      )
    # # A tibble: 5 x 3
    #      id stage flag 
    #   <int> <chr> <chr>
    # 1     1 D     Dance
    # 2     2 D     Dance
    # 3     3 D     Dance
    # 4     4 D     Dance
    # 5     5 D     Dance
    

    但是,使用left_join 的替代方法可以避免case_when 的分段操作。

    acronyms <- data.frame(
      prio  = 1:4,
      stage = c("D", "C", "B", "A"),
      flag  = c("Dance", "Climb", "Biceps", "Aerobic")
    )
    
    expand.grid(id=c(1:5), stage = LETTERS[1:4]) %>%
      left_join(acronyms) %>%
      arrange(id, prio) %>%
      group_by(id) %>%
      slice(1) %>%
      select(-prio) %>%
      ungroup()
    

    acronyms 中的基本stage/flag 关联基本上就足够了;我添加了prio,这是一种确定性且简单的方法,可以始终为每个id 获取最重要的信息。根据您的最终需求,这里可能还有其他有用的技巧。

    【讨论】:

    • 我正要评论 intersect 方法,我更喜欢 left_join 方法,看起来是一种更规范的方法
    • intersect 只是为了找到最理想的阶段并保留它(第一个向量的顺序很重要);它在连接选项中被prio 取代。
    猜你喜欢
    • 2015-01-03
    • 2021-01-14
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    相关资源
    最近更新 更多