【问题标题】:How to get quantiles to work with summarise_at and group_by (dplyr)如何让分位数与 summarise_at 和 group_by (dplyr) 一起使用
【发布时间】:2020-01-18 08:59:49
【问题描述】:

当使用dplyr 创建一个按变量级别组织的汇总统计表时,我无法弄清楚计算四分位数的语法,而无需重复列名。也就是说,使用诸如vars()list() 之类的调用可以与mean()median() 等其他函数一起使用,但不能与quantile() 一起使用

搜索产生了不再有效的过时解决方案,因为它们使用了已弃用的调用,例如 do() 和/或 funs()

data(iris)
library(tidyverse)

#This works: Notice I have not attempted to calculate quartiles yet
summary_stat <- iris %>% 
  group_by(Species) %>% 
  summarise_at(vars(Sepal.Length), 
               list(min=min, median=median, max=max,
               mean=mean, sd=sd)
               )
A tibble: 3 x 6
  Species      min median   max  mean    sd
  <fct>      <dbl>  <dbl> <dbl> <dbl> <dbl>
1 setosa       4.3    5     5.8  5.01 0.352
2 versicolor   4.9    5.9   7    5.94 0.516
3 virginica    4.9    6.5   7.9  6.59 0.636

##########################################################################
#Does NOT work:
five_number_summary <- iris %>% 
  group_by(Species) %>% 
  summarise_at(vars(Sepal.Length),
               list(min=min, Q1=quantile(.,probs = 0.25),
                    median=median, Q3=quantile(., probs = 0.75),
                    max=max))

Error: Must use a vector in `[`, not an object of class matrix.
Call `rlang::last_error()` to see a backtrace

###########################################################################
#This works: Remove the vars() argument, remove the list() argument,
  #replace summarise_at() with summarise()
  #but the code requires repeating the column name (Sepal.Length)

five_number_summary <- iris %>% 
  group_by(Species) %>% 
  summarise(min=min(Sepal.Length), 
            Q1=quantile(Sepal.Length,probs = 0.25),
            median=median(Sepal.Length), 
            Q3=quantile(Sepal.Length, probs = 0.75),
            max=max(Sepal.Length))

# A tibble: 3 x 6
  Species      min    Q1 median    Q3   max
  <fct>      <dbl> <dbl>  <dbl> <dbl> <dbl>
1 setosa       4.3  4.8     5     5.2   5.8
2 versicolor   4.9  5.6     5.9   6.3   7  
3 virginica    4.9  6.22    6.5   6.9   7.9

最后一段代码完全符合我的要求,但我想知道为什么没有更短的语法不会强迫我重复变量。

【问题讨论】:

    标签: r dplyr quantile


    【解决方案1】:

    您可以创建一个列表列,然后使用unnest_wider,这需要tidyr 1.0.0

    library(tidyverse)
    
    iris %>% 
      group_by(Species) %>% 
      summarise(q = list(quantile(Sepal.Length))) %>% 
      unnest_wider(q)
    
    # # A tibble: 3 x 6
    #   Species     `0%` `25%` `50%` `75%` `100%`
    #   <fct>      <dbl> <dbl> <dbl> <dbl>  <dbl>
    # 1 setosa       4.3  4.8    5     5.2    5.8
    # 2 versicolor   4.9  5.6    5.9   6.3    7  
    # 3 virginica    4.9  6.22   6.5   6.9    7.9
    

    有一个 names_repair 参数,但显然这会更改所有列的名称,而不仅仅是未嵌套的列 (??)

    iris %>% 
      group_by(Species) %>% 
      summarise(q = list(quantile(Sepal.Length))) %>% 
      unnest_wider(q, names_repair = ~paste0('Q_', sub('%', '', .)))
    
    # # A tibble: 3 x 6
    #   Q_Species    Q_0  Q_25  Q_50  Q_75 Q_100
    #   <fct>      <dbl> <dbl> <dbl> <dbl> <dbl>
    # 1 setosa       4.3  4.8    5     5.2   5.8
    # 2 versicolor   4.9  5.6    5.9   6.3   7  
    # 3 virginica    4.9  6.22   6.5   6.9   7.9
    

    另一个选项是group_modify

    iris %>% 
      group_by(Species) %>% 
      group_modify(~as.data.frame(t(quantile(.$Sepal.Length))))
    
    # # A tibble: 3 x 6
    # # Groups:   Species [3]
    #   Species     `0%` `25%` `50%` `75%` `100%`
    #   <fct>      <dbl> <dbl> <dbl> <dbl>  <dbl>
    # 1 setosa       4.3  4.8    5     5.2    5.8
    # 2 versicolor   4.9  5.6    5.9   6.3    7  
    # 3 virginica    4.9  6.22   6.5   6.9    7.9
    

    或者你可以使用 data.table

    library(data.table)
    irisdt <- as.data.table(iris)
    
    irisdt[, as.list(quantile(Sepal.Length)), Species]
    #       Species  0%   25% 50% 75% 100%
    # 1:     setosa 4.3 4.800 5.0 5.2  5.8
    # 2: versicolor 4.9 5.600 5.9 6.3  7.0
    # 3:  virginica 4.9 6.225 6.5 6.9  7.9
    

    【讨论】:

      【解决方案2】:

      您在失败的summarise_at 调用中缺少quantile 函数前面的~。请尝试以下操作:

      five_number_summary <- iris %>% 
        group_by(Species) %>% 
        summarise_at(vars(Sepal.Length),
                     list(min=min, Q1=~quantile(., probs = 0.25),
                          median=median, Q3=~quantile(., probs = 0.75),
                          max=max))
      five_number_summary
      # A tibble: 3 x 6
        Species      min    Q1 median    Q3   max
        <fct>      <dbl> <dbl>  <dbl> <dbl> <dbl>
      1 setosa       4.3  4.8     5     5.2   5.8
      2 versicolor   4.9  5.6     5.9   6.3   7  
      3 virginica    4.9  6.22    6.5   6.9   7.9
      

      【讨论】:

      • 谢谢@Arienrhod。 ~ 的意义是什么?为什么只有quantile()函数需要~而不需要其他函数?
      • 据我所知~function(x){...} 的简写。没有它,R 会尝试计算表达式 quantile...,但在这种情况下会失败。 ~ 经常在 purrr 函数中使用,您可以找到更多信息 herehere
      【解决方案3】:

      关于@arienrhod 更新版本的说明

      library(dplyr,quietly = TRUE,verbose = FALSE, warn.conflicts = FALSE)
      five_number_summary <- iris %>% 
        group_by(Species) %>% 
        summarise(across(Sepal.Length, list(min=min, Q1=~quantile(., probs = 0.25),
                          median=median, Q3=~quantile(., probs = 0.75),
                          max=max),  .names = "{.fn}"))
      five_number_summary
      #> # A tibble: 3 x 6
      #>   Species      min    Q1 median    Q3   max
      #>   <fct>      <dbl> <dbl>  <dbl> <dbl> <dbl>
      #> 1 setosa       4.3  4.8     5     5.2   5.8
      #> 2 versicolor   4.9  5.6     5.9   6.3   7  
      #> 3 virginica    4.9  6.22    6.5   6.9   7.9
      

      reprex package (v2.0.1) 于 2022-02-21 创建

      【讨论】:

        猜你喜欢
        • 2016-10-17
        • 2018-04-09
        • 1970-01-01
        • 2018-02-03
        • 1970-01-01
        • 2021-07-20
        • 1970-01-01
        • 2019-11-29
        • 2015-03-29
        相关资源
        最近更新 更多