I need to compute several quantiles from a single numeric vector and use dplyr::summarise
for that. Here's what I have :
library(dplyr)
library(rlang)
quantiles <- function(data, group, ...){
group <- enquo(group)
value_vars <- quos(...)
data %>%
group_by(!!group) %>%
summarise_at(vars(!!!value_vars), funs(
median = median,
q1 = quantile(., probs = 0.25),
q3 = quantile(., probs = 0.75))
) %>%
ungroup()
}
quantiles(data = iris, group = Species, Sepal.Length, Petal.Width)
It works but triggers the note of no visible binding for variable '.' when checking the package. So I'm looking for a way to get rid of .
in the function. I can substitute a mutate_at
to summarise_at
then summarise with first
, but it can get quite heavy :
quantiles <- function(data, group, ...){
group <- enquo(group)
value_vars <- quos(...)
data %>%
group_by(!!group) %>%
mutate_at(vars(!!!value_vars), funs(median = median)) %>%
mutate_at(vars(!!!value_vars), funs(q1 = quantile), probs = 0.25) %>%
mutate_at(vars(!!!value_vars), funs(q3 = quantile), probs = 0.75) %>%
summarise_at(vars(matches('(median|q1|q3)$')), first) %>%
ungroup()
}
quantiles(data = iris, group = Species, Sepal.Length, Petal.Width)
edit : use purrr:map2
I can build a list of functions with the desired secondary argument values :
quantile_funs <- purrr::map2(
.x = list(median = median, q1 = quantile, q3 = quantile),
.y = list(NULL, 0.25, 0.75),
.f = function(fun, arg){
function(x) fun(x, probs = arg)
}
)
quantiles <- function(data, group, ...){
group <- enquo(group)
value_vars <- quos(...)
data %>%
group_by(!!group) %>%
summarise_at(vars(!!!value_vars), .funs = quantile_funs) %>%
ungroup()
}
quantiles(data = iris, group = Species, Sepal.Length, Petal.Width)
This works well, but due to luck since mean
has an ...
argument which allows me to actually do mean(x, probs = NULL)
while it does not have any probs
argument.
I tried the following but it did not work :
quantile_funs <- purrr::map2(
.x = list(median = median, q1 = quantile, q3 = quantile),
.y = list(list(NULL = NULL), list(probs = 0.25), list(probs = 0.75)),
.f = function(fun, arg){
function(x) fun(x, splice(arg))
}
)