【问题标题】:Dplyr group_by summarize keep min/max value for each column within group, depending on column suffixDplyr group_by summarise 保留组内每列的最小值/最大值,具体取决于列后缀
【发布时间】:2019-10-28 06:14:17
【问题描述】:

我有一个数据框,其中包含我想折叠成单个条目的组,新行的值是每个组中的最小值或最大值,具体取决于列名。

例如,给定:

set.seed(1)
dat <- data.frame(grp = c('A', 'A', 'B', 'B'), 
                  v1_high = rnorm(4), 
                  v2_high = rnorm(4), 
                  v3_low = rnorm(4))
# original
   grp    v1_high    v2_high     v3_low
 1   A -0.6264538  0.3295078  0.5757814
 2   A  0.1836433 -0.8204684 -0.3053884
 3   B -0.8356286  0.4874291  1.5117812
 4   B  1.5952808  0.7383247  0.3898432

我想生成一个新数据框,其中包含与“A”和“B”组对应的两个条目,每列的最大值以_high 结尾,每列的最小值以_low 结尾。

在这种情况下:

# desired result
  grp   v1_high   v2_high     v3_low
1   A 0.1836433 0.3295078 -0.3053884
2   B 1.5952808 0.7383247  0.3898432

最后,这些列的数量和名称是事先不知道的。

理想情况下,摘要还可以处理不存在_min 列而只有_max 列的情况,尽管我总是可以手动检查这种情况并使用if () { .. } 分别处理这两种情况声明。

有什么建议吗?使用summarize_at() 函数似乎应该可以做到这一点,但我还没有弄清楚如何将不同的函数应用于不同的列集。

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    一个选项是按'grp'分组,获取以'high'(列名)结尾的列的max,也将其用作分组列并获取以'结尾的列的min低'

    library(dplyr)    
    dat %>%
       group_by(grp) %>%  
       mutate_at(vars(ends_with('high')), max) %>% 
       group_by_at(vars(ends_with('high')), .add = TRUE) %>% 
       summarise_at(vars(ends_with('low')), min)
    # A tibble: 2 x 4
    # Groups:   grp, v1_high [2]
    #  grp   v1_high v2_high v3_low
    #  <fct>   <dbl>   <dbl>  <dbl>
    #1 A       0.184   0.330 -0.305
    #2 B       1.60    0.738  0.390
    

    如果没有min 列,它也可以工作

    dat[-4] %>%
        group_by(grp) %>%  
        mutate_at(vars(ends_with('high')), max) %>% 
        group_by_at(vars(ends_with('high')), .add = TRUE) %>%   
        summarise_at(vars(ends_with('low')), min)
    # A tibble: 2 x 3
    # Groups:   grp, v1_high [2]
    #  grp   v1_high v2_high
    #  <fct>   <dbl>   <dbl>
    #1 A       0.184   0.330
    #2 B       1.60    0.738
    

    或者另一个选项是map2

    library(purrr)
    map2(list(min, max), list('low', 'high'), ~ 
          dat %>% 
             select(grp, ends_with(.y)) %>%
             group_by(grp) %>%
             summarise_all(.x)) %>% 
             reduce(inner_join, by = 'grp')
    

    【讨论】:

    • @KeithHughitt 感谢您的回复。我还添加了一个基于map2 的解决方案,以防您想使用更多功能进行概括
    猜你喜欢
    • 1970-01-01
    • 2015-01-09
    • 2020-03-04
    • 2022-06-11
    • 2021-08-04
    • 2018-10-30
    • 2017-12-27
    • 2018-05-14
    • 1970-01-01
    相关资源
    最近更新 更多