如何在 dplyr 总结中组合不同的输入变量和不同的函数
How do I combine varying input variables and varying functions in dplyr summarise
我需要对数据框进行分组和汇总,根据要汇总的变量使用不同的汇总函数。这些函数可以有不同的主要参数和可选参数,我想编写一个可以完成所有这些的函数。
以下是我设法编写的更简单的函数,只是为了展示它的逻辑。
require(tidyverse)
require(magrittr)
require(rlang)
example <- data.frame(y = as.factor(c('A','B','C','A','B')),
x1 = c(7, 10, NA, NA, 2),
x2 = c(13, 0, 0, 2, 1),
z = c(0, 1, 0, 1, 0))
# Summarise variables with common prefix
do_summary_prefix <- function(dataset, y, prefix, fun, ...){
y <- enquo(y)
prefix <- quo_name(enquo(prefix))
fun <- match.fun(fun)
dataset %<>%
group_by(!!y) %>%
summarise_at(vars(starts_with(prefix)), funs(fun), ...) %>%
ungroup()
return(dataset)
}
do_summary_prefix(example, y, x, 'quantile', probs = 0.25, na.rm = T)
# Summarise variables with different names, one at a time
do_summary_x <- function(dataset, y, x, fun, ...){
y <- enquo(y)
x <- enquo(x)
dataset %<>%
group_by(!!y) %>%
summarise(!!paste(quo_name(x), fun, sep = '_') := do.call(match.fun(fun), list(x = !!x, ...))) %>%
ungroup()
return(dataset)
}
do_summary_x(example, y, x1, fun = 'mean', na.rm = F)
这对我来说没问题,我可以使用 do_summary_x
对我想要总结的变量进行循环以完成工作。但我想将循环集成到更高级别的函数中,利用 ...
,同时仍然能够为我的汇总函数使用不同的参数。
我知道我不能将 ...
用于不同的子级函数,所以我将传递前一个(我的变量或函数参数)作为列表,并使用 do.call
.对我来说更自然的做法是为输入变量保留 ...
并添加始终命名的带有列表的参数。这就是我的目的:
#install.packages('plyr') # if needed
join_all <- plyr::join_all
do_summary <- function(dataset, y, ..., fun, other_args = list(NULL =
NULL)){
y_quo <- enquo(y)
y_name <- quo_name(y_quo)
values <- quos(...)
datasets <- lapply(values, function(value){
summarised_data <- dataset %>%
group_by(!!y_quo) %>%
summarise(calcul = do.call(fun,
unlist(list(list(x = !!value),
other_args),
recursive = F))) %>%
ungroup() %>%
rename(!!paste(quo_name(value), stat, sep = '_') := calcul)
return(summarised_data)
})
finished <- join_all(datasets, by = y_name, type = 'left')
return(finished)
}
do_summary(example, y,
x1, x2, z,
stat = 'quantile',
other_args = list(probs = 0.1, na.rm = T))
do_summary(example, y,
x1, x2, z,
fun = 'mean')
这工作正常,所以我总体上很满意,但这只适用于具有 x
第一个参数的函数。
假设我还想更改 fun
的第一个参数的名称,即此处的 x
。我该怎么办?
我还没有找到一个解决方案来引用然后在 do.call
中注入类似 changing_arg = !!x
的东西,或者合理地使用 list(!!changing_arg := !!x)
以下是我将如何简化您的函数:
library(dplyr)
library(rlang)
do_summary <- function(dataset, y, ..., fun, other_args = list(NULL = NULL)){
y_quo <- enquo(y)
values <- quos(...)
datasets <- dataset %>%
group_by(!!y_quo) %>%
summarise_at(vars(!!!values), .funs = fun, !!!other_args) %>%
rename_at(vars(!!!values), paste, fun, sep = "_")
return(datasets)
}
do_summary(example, y,
x1, x2, z,
fun = 'quantile',
other_args = list(probs = 0.1, na.rm = T))
do_summary(example, y,
x1, x2, z,
fun = 'mean')
结果:
# A tibble: 3 x 4
y x1_quantile x2_quantile z_quantile
<fctr> <dbl> <dbl> <dbl>
1 A 7.0 3.1 0.1
2 B 2.8 0.1 0.1
3 C NA 0.0 0.0
# A tibble: 3 x 4
y x1_mean x2_mean z_mean
<fctr> <dbl> <dbl> <dbl>
1 A NA 7.5 0.5
2 B 6 0.5 0.5
3 C NA 0.0 0.0
备注:
而不是使用 lapply
循环遍历每个 values
,您可以简单地使用 summarise_at
和 rename_at
并提供 values
通过使用 !!!
显式拼接到 vars
。
fun
然后提供给 summarise_at
的 .funs
参数,同样,您可以显式拼接 other_args
和 !!!
.例如 list(probs = 0.1, na.rm = T)
变成 probs = 0.1, na.rm = T
.
rename_at
的想法相同。使用vars
并显式拼接values
。另一种方法是编写 rename_at(vars(-y_name), ...)
,因为 summarise_at
returns 仅对列和汇总列进行分组。
这个方法去掉了lapply
,summarise
和中的尴尬do.call
join_all
最后(y_name
因此也不需要)。
你最后的 do_summary
调用 quantile
似乎是一个错字,而不是 stat = "quantile"
,我想你的意思是 fun = "quantile"
请注意,此函数仅在您以字符串形式提供函数名称时才有效。
我需要对数据框进行分组和汇总,根据要汇总的变量使用不同的汇总函数。这些函数可以有不同的主要参数和可选参数,我想编写一个可以完成所有这些的函数。
以下是我设法编写的更简单的函数,只是为了展示它的逻辑。
require(tidyverse)
require(magrittr)
require(rlang)
example <- data.frame(y = as.factor(c('A','B','C','A','B')),
x1 = c(7, 10, NA, NA, 2),
x2 = c(13, 0, 0, 2, 1),
z = c(0, 1, 0, 1, 0))
# Summarise variables with common prefix
do_summary_prefix <- function(dataset, y, prefix, fun, ...){
y <- enquo(y)
prefix <- quo_name(enquo(prefix))
fun <- match.fun(fun)
dataset %<>%
group_by(!!y) %>%
summarise_at(vars(starts_with(prefix)), funs(fun), ...) %>%
ungroup()
return(dataset)
}
do_summary_prefix(example, y, x, 'quantile', probs = 0.25, na.rm = T)
# Summarise variables with different names, one at a time
do_summary_x <- function(dataset, y, x, fun, ...){
y <- enquo(y)
x <- enquo(x)
dataset %<>%
group_by(!!y) %>%
summarise(!!paste(quo_name(x), fun, sep = '_') := do.call(match.fun(fun), list(x = !!x, ...))) %>%
ungroup()
return(dataset)
}
do_summary_x(example, y, x1, fun = 'mean', na.rm = F)
这对我来说没问题,我可以使用 do_summary_x
对我想要总结的变量进行循环以完成工作。但我想将循环集成到更高级别的函数中,利用 ...
,同时仍然能够为我的汇总函数使用不同的参数。
我知道我不能将 ...
用于不同的子级函数,所以我将传递前一个(我的变量或函数参数)作为列表,并使用 do.call
.对我来说更自然的做法是为输入变量保留 ...
并添加始终命名的带有列表的参数。这就是我的目的:
#install.packages('plyr') # if needed
join_all <- plyr::join_all
do_summary <- function(dataset, y, ..., fun, other_args = list(NULL =
NULL)){
y_quo <- enquo(y)
y_name <- quo_name(y_quo)
values <- quos(...)
datasets <- lapply(values, function(value){
summarised_data <- dataset %>%
group_by(!!y_quo) %>%
summarise(calcul = do.call(fun,
unlist(list(list(x = !!value),
other_args),
recursive = F))) %>%
ungroup() %>%
rename(!!paste(quo_name(value), stat, sep = '_') := calcul)
return(summarised_data)
})
finished <- join_all(datasets, by = y_name, type = 'left')
return(finished)
}
do_summary(example, y,
x1, x2, z,
stat = 'quantile',
other_args = list(probs = 0.1, na.rm = T))
do_summary(example, y,
x1, x2, z,
fun = 'mean')
这工作正常,所以我总体上很满意,但这只适用于具有 x
第一个参数的函数。
假设我还想更改 fun
的第一个参数的名称,即此处的 x
。我该怎么办?
我还没有找到一个解决方案来引用然后在 do.call
中注入类似 changing_arg = !!x
的东西,或者合理地使用 list(!!changing_arg := !!x)
以下是我将如何简化您的函数:
library(dplyr)
library(rlang)
do_summary <- function(dataset, y, ..., fun, other_args = list(NULL = NULL)){
y_quo <- enquo(y)
values <- quos(...)
datasets <- dataset %>%
group_by(!!y_quo) %>%
summarise_at(vars(!!!values), .funs = fun, !!!other_args) %>%
rename_at(vars(!!!values), paste, fun, sep = "_")
return(datasets)
}
do_summary(example, y,
x1, x2, z,
fun = 'quantile',
other_args = list(probs = 0.1, na.rm = T))
do_summary(example, y,
x1, x2, z,
fun = 'mean')
结果:
# A tibble: 3 x 4
y x1_quantile x2_quantile z_quantile
<fctr> <dbl> <dbl> <dbl>
1 A 7.0 3.1 0.1
2 B 2.8 0.1 0.1
3 C NA 0.0 0.0
# A tibble: 3 x 4
y x1_mean x2_mean z_mean
<fctr> <dbl> <dbl> <dbl>
1 A NA 7.5 0.5
2 B 6 0.5 0.5
3 C NA 0.0 0.0
备注:
而不是使用
lapply
循环遍历每个values
,您可以简单地使用summarise_at
和rename_at
并提供values
通过使用!!!
显式拼接到vars
。fun
然后提供给summarise_at
的.funs
参数,同样,您可以显式拼接other_args
和!!!
.例如list(probs = 0.1, na.rm = T)
变成probs = 0.1, na.rm = T
.rename_at
的想法相同。使用vars
并显式拼接values
。另一种方法是编写rename_at(vars(-y_name), ...)
,因为summarise_at
returns 仅对列和汇总列进行分组。这个方法去掉了
lapply
,summarise
和中的尴尬do.call
join_all
最后(y_name
因此也不需要)。你最后的
do_summary
调用quantile
似乎是一个错字,而不是stat = "quantile"
,我想你的意思是fun = "quantile"
请注意,此函数仅在您以字符串形式提供函数名称时才有效。