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

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

使用mtcars数据集,如果我想查看第25,50和75百分位数以及汽缸数(“cyl”)的每加仑英里数(“mpg”)的平均值和计数,我使用以下代码:

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等)更干净地执行此操作? 干净,我的意思是没有“做”声明。

谢谢


如果你想使用purrr::map ,你可以这样做!

library(dplyr)
library(tidyr)
library(broom)
library(purrr)

mtcars %>%
  nest(-cyl) %>%
  mutate(Quantiles = map(data, ~ quantile(.$mpg))) %>% 
  unnest(map(Quantiles, tidy))

#> # A tibble: 15 × 3
#>      cyl names     x
#>    <dbl> <chr> <dbl>
#> 1      6    0% 17.80
#> 2      6   25% 18.65
#> 3      6   50% 19.70
#> 4      6   75% 21.00
#> 5      6  100% 21.40
#> 6      4    0% 21.40
#> 7      4   25% 22.80
#> 8      4   50% 26.00
#> 9      4   75% 30.40
#> 10     4  100% 33.90
#> 11     8    0% 10.40
#> 12     8   25% 14.40
#> 13     8   50% 15.20
#> 14     8   75% 16.25
#> 15     8  100% 19.20

这种方法的一个好处是输出是整齐的,每行一个观察值。


这是一个dplyr方法,可以避免do但需要单独调用quantile来计算每个分位数值。

mtcars %>% group_by(cyl) %>%
  summarise(`25%`=quantile(mpg, probs=0.25),
            `50%`=quantile(mpg, probs=0.5),
            `75%`=quantile(mpg, probs=0.75),
            avg=mean(mpg),
            n=n())

  cyl   25%  50%   75%      avg  n
1   4 22.80 26.0 30.40 26.66364 11
2   6 18.65 19.7 21.00 19.74286  7
3   8 14.40 15.2 16.25 15.10000 14

如果summarise可以通过一次调用quantile来返回多个值,那将会更好,但这似乎是dplyr开发中的一个公开问题。

更新:这是@ JuliaSilge的答案的变体,它使用嵌套获取分位数,但不使用map 。 但是,它确实需要额外的代码行来添加列出分位数级别的列,因为我不知道如何(或者如果可能的话)直接从quantile调用中将分位数的名称捕获到单独的列中。

p = c(0.25,0.5,0.75)

mtcars %>% 
  group_by(cyl) %>% 
  summarise(quantiles = list(sprintf("%1.0f%%", p*100)),
            mpg = list(quantile(mpg, p))) %>% 
  unnest
    cyl quantiles   mpg
1     4       25% 22.80
2     4       50% 26.00
3     4       75% 30.40
4     6       25% 18.65
5     6       50% 19.70
6     6       75% 21.00
7     8       25% 14.40
8     8       50% 15.20
9     8       75% 16.25

这是一种使用broom包的tidy()函数的dplyr方法,但不幸的是它仍然需要do() ,但它要简单得多。

library(dplyr)
library(broom)

mtcars %>%
    group_by(cyl) %>%
    do( tidy(t(quantile(.$mpg))) )

这使:

    cyl   X0.  X25.  X50.  X75. X100.
  (dbl) (dbl) (dbl) (dbl) (dbl) (dbl)
1     4  21.4 22.80  26.0 30.40  33.9
2     6  17.8 18.65  19.7 21.00  21.4
3     8  10.4 14.40  15.2 16.25  19.2

请注意使用t()因为broom包没有命名数字的方法。

这是基于我以前对summary()的回答。

链接地址: http://www.djcxy.com/p/24837.html

上一篇: Using dplyr window functions to calculate percentiles

下一篇: How to make a reproducible example of a database connection?