我有一个有效的解决方案,但我正在寻找一个更清晰,更易读的解决方案,可能会利用一些较新的dplyr窗口函数 .
使用mtcars数据集,如果我想查看第25,第50,第75百分位数以及每加仑英里数(“mpg”)和气缸数(“cyl”),我使用以下代码:
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等)更干净地完成这项工作?干净利落,我的意思是没有“做”声明 .
谢谢
8 回答
如果您正在使用
purrr::map
,您可以这样做!由reprex包创建于2018-11-10(v0.2.1)
这种方法的一个好处是输出整齐,每行一次观察 .
UPDATE 2: 使用
enframe
将以前版本的summarise()
转换为单行的另一个更新:这可以使用tidyeval转换为更通用的功能:
UPDATE: 这里's a variation on @JuliaSilge'的答案使用嵌套来获取分位数,但不使用
map
. 但是,它确实需要额外的代码行来添加列出分位数级别的列,因为我可以直接从调用quantile
中将分位数的名称捕获到单独的列中 .ORIGINAL ANSWER
这是一个避免
do
的方法,但需要为每个分位数值单独调用quantile
.如果
summarise
可以通过单次调用quantile
返回多个值会更好,但这似乎是dplyr
在dplyr
开发中 .这是一个使用
broom
包的tidy()
函数的方法,遗憾的是它仍然需要do()
,但它要简单得多 .这使:
请注意
t()
的使用,因为broom
包没有命名数字的方法 .这是基于我的earlier answer for summary() here .
不确定如何避免
dplyr
中的do()
,但是您可以使用c()
和as.list()
以data.table
以非常简单的方式执行此操作:如果您希望它们按
cyl
列排序,请将by
替换为keyby
.此解决方案仅使用
dplyr
和tidyr
,允许您在dplyr
链中指定分位数,并在分组和汇总之前利用tidyr::crossing()
到"stack"数据集的多个副本 .结果:
unique()
是必要的,让dplyr::summarise()
知道您只需要每个组一个值 .这是一个相当可读的解决方案,它使用
dplyr
和purrr
以整齐的格式返回分位数:Code
Result
以下是使用
dplyr
,purrr
和rlang
组合的解决方案:由reprex package(v0.2.0)创建于2018-10-01 .
do()
实际上是正确的习惯用法,因为它是专为分组转换而设计的 . 可以将其视为映射数据帧组的lapply()
. (对于这样一个专门的函数,像“do”这样的通用名称并不理想 . 但改变它可能为时已晚 . )在每个
cyl
组中,您希望将quantile()
应用于mpg
列:除非这不起作用,因为
quantile()
不返回数据帧;你必须明确地转换它的输出 . 由于此更改相当于使用数据框包装quantile()
,因此可以使用gestalt函数组合运算符%>>>%
: