使用dplyr窗口函数计算百分位数

65

我有一个可行的解决方案,但正在寻找一种更加清晰、易读,可能利用一些较新的dplyr窗口函数的解决方案。

使用mtcars数据集,如果我想查看每个气缸数("cyl")对应的平均数和数量以及每加仑英里数("mpg")的第25,50,75百分位数,则使用以下代码:

library(dplyr)
library(tidyr)

# load data
data("mtcars")

# Percentiles used in calculation
p <- c(.25,.5,.75)

# old dplyr solution 
mtcars %>% group_by(cyl) %>% 
  do(data.frame(p=p, stats=quantile(.$mpg, probs=p), 
                n = length(.$mpg), avg = mean(.$mpg))) %>%
  spread(p, stats) %>%
  select(1, 4:6, 3, 2)

# note: the select and spread statements are just to get the data into
#       the format in which I'd like to see it, but are not critical

是否有一种更干净的方法可以使用dplyr中的部分汇总函数(n_tiles,percent_rank等)来完成这个操作?通过“干净”我指的是不使用“do”语句。

谢谢


我应该补充说明这段代码还使用了“tidyr”包,其中“spread”函数也是从那里来的。 - dreww2
11个回答

0

do()实际上是正确的习惯用语,因为它被设计用于组内转换。可以将其视为在数据框的一组上映射的lapply()。(对于这样一个专门的函数来说,“do”这样的通用名称并不理想。但现在可能为时已晚了。)

道德上,在每个 组内,您希望将quantile()应用于mpg列:

library(dplyr)

p <- c(.2, .5, .75)

mtcars %>% 
  group_by(cyl) %>%
  do(quantile(.$mpg, p))

#> Error: Results 1, 2, 3 must be data frames, not numeric

但是这并不起作用,因为quantile()不返回数据框; 您必须显式地转换其输出。由于此更改相当于使用数据框包装quantile(),因此您可以使用gestalt函数组合运算符%>>>%

library(gestalt)
library(tibble)

quantile_tbl <- quantile %>>>% enframe("quantile")

mtcars %>% 
  group_by(cyl) %>%
  do(quantile_tbl(.$mpg, p))

#> # A tibble: 9 x 3
#> # Groups:   cyl [3]
#>     cyl quantile value
#>   <dbl> <chr>    <dbl>
#> 1     4 20%       22.8
#> 2     4 50%       26  
#> 3     4 75%       30.4
#> 4     6 20%       18.3
#> 5     6 50%       19.7
#> 6     6 75%       21  
#> 7     8 20%       13.9
#> 8     8 50%       15.2
#> 9     8 75%       16.2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接