按函数替换多个 `summarize` 语句
Replace multiple `summarize`statements by function
我目前正在重复很多代码,因为我需要 summarize
始终为不同的组使用相同的列。我如何通过只编写一次 summarize
函数(始终相同)来有效地做到这一点,但逐个定义输出名称和 group_by
参数?
一个最小的例子:
col1 <- c("UK", "US", "UK", "US")
col2 <- c("Tech", "Social", "Social", "Tech")
col3 <- c("0-5years", "6-10years", "0-5years", "0-5years")
col4 <- 1:4
col5 <- 5:8
df <- data.frame(col1, col2, col3, col4, col5)
result1 <- df %>%
group_by(col1, col2) %>%
summarize(sum1 = sum(col4, col5))
result2 <- df %>%
group_by(col2, col3) %>%
summarize(sum1 = sum(col4, col5))
result3 <- df %>%
group_by(col1, col3) %>%
summarize(sum1 = sum(col4, col5))
使用 combn:
combn(colnames(df)[1:3], 2, FUN = function(x){
df %>%
group_by(.dots = x) %>%
summarize(sum1 = sum(col4, col5))
}, simplify = FALSE)
首先,您需要使用这样的函数计算变量:
library(tidyverse)
res_func <- function(x, y){
df %>%
group_by(!!as.symbol(x), !!as.symbol(y)) %>%
summarize(sum1 = sum(col4, col5))
}
很有魅力:
res_func("col1", "col2")
# A tibble: 4 x 3
# Groups: col1 [2]
col1 col2 sum1
<fct> <fct> <int>
1 UK Social 10
2 UK Tech 6
3 US Social 8
4 US Tech 12
我们可以使用 assign
创建一个函数,根据您通过函数传入的参数命名您的框架:
res_func2 <- function(x, y){
assign(paste0("result_", x, y),
df %>%
group_by(!!as.symbol(x), !!as.symbol(y)) %>%
summarize(sum1 = sum(col4, col5)),
envir = parent.frame())
}
这将通过 运行 res_func2("col1", "col2")
创建一个名为 result_col1col2
的新 df
> result_col1col2
# A tibble: 4 x 3
# Groups: col1 [2]
col1 col2 sum1
<fct> <fct> <int>
1 UK Social 10
2 UK Tech 6
3 US Social 8
4 US Tech 12
要在自己的函数中使用dplyr,可以使用tidy evaluation。原因是 dplyr 评估 dplyr 代码的方式,称为非标准评估,它包装了所有不像普通 R 代码那样表现的东西。我建议阅读此内容:
https://tidyeval.tidyverse.org/modifying-inputs.html#modifying-quoted-expressions
summarizefunction <- function(data, ..., sumvar1, sumvar2) {
groups <- enquos(...)
sumvar1 <- enquo(sumvar1)
sumvar2 <- enquo(sumvar2)
result <- data %>%
group_by(!!!groups) %>%
summarise(sum1 = sum(!!sumvar1, !!sumvar2))
return(result)
}
summarizefunction(df, col1, col2, sumvar1 = col4, sumvar2 = col5)
您可以使用 enquo
关键字来包装引号参数,以防止它们被立即计算。您可以使用 !!
(称为 bang bang)运算符取消对参数的引用。我认为这是最灵活和可重用的解决方案,即使您必须编写一些更多的初始代码。
您也可以在这些情况下使用 purrr::partial
:
library(purrr)
summarize45 <- partial(summarize, sum1 = sum(col4, col5))
result1b <- df %>%
group_by(col1, col2) %>%
summarize45()
identical(result1, result1b)
# [1] TRUE
或更进一步:
gb_df <- partial(group_by, df)
result1c <- gb_df(col1, col2) %>% summarize45()
identical(result1, result1c)
# [1] TRUE
我目前正在重复很多代码,因为我需要 summarize
始终为不同的组使用相同的列。我如何通过只编写一次 summarize
函数(始终相同)来有效地做到这一点,但逐个定义输出名称和 group_by
参数?
一个最小的例子:
col1 <- c("UK", "US", "UK", "US")
col2 <- c("Tech", "Social", "Social", "Tech")
col3 <- c("0-5years", "6-10years", "0-5years", "0-5years")
col4 <- 1:4
col5 <- 5:8
df <- data.frame(col1, col2, col3, col4, col5)
result1 <- df %>%
group_by(col1, col2) %>%
summarize(sum1 = sum(col4, col5))
result2 <- df %>%
group_by(col2, col3) %>%
summarize(sum1 = sum(col4, col5))
result3 <- df %>%
group_by(col1, col3) %>%
summarize(sum1 = sum(col4, col5))
使用 combn:
combn(colnames(df)[1:3], 2, FUN = function(x){
df %>%
group_by(.dots = x) %>%
summarize(sum1 = sum(col4, col5))
}, simplify = FALSE)
首先,您需要使用这样的函数计算变量:
library(tidyverse)
res_func <- function(x, y){
df %>%
group_by(!!as.symbol(x), !!as.symbol(y)) %>%
summarize(sum1 = sum(col4, col5))
}
很有魅力:
res_func("col1", "col2")
# A tibble: 4 x 3
# Groups: col1 [2]
col1 col2 sum1
<fct> <fct> <int>
1 UK Social 10
2 UK Tech 6
3 US Social 8
4 US Tech 12
我们可以使用 assign
创建一个函数,根据您通过函数传入的参数命名您的框架:
res_func2 <- function(x, y){
assign(paste0("result_", x, y),
df %>%
group_by(!!as.symbol(x), !!as.symbol(y)) %>%
summarize(sum1 = sum(col4, col5)),
envir = parent.frame())
}
这将通过 运行 res_func2("col1", "col2")
result_col1col2
的新 df
> result_col1col2
# A tibble: 4 x 3
# Groups: col1 [2]
col1 col2 sum1
<fct> <fct> <int>
1 UK Social 10
2 UK Tech 6
3 US Social 8
4 US Tech 12
要在自己的函数中使用dplyr,可以使用tidy evaluation。原因是 dplyr 评估 dplyr 代码的方式,称为非标准评估,它包装了所有不像普通 R 代码那样表现的东西。我建议阅读此内容:
https://tidyeval.tidyverse.org/modifying-inputs.html#modifying-quoted-expressions
summarizefunction <- function(data, ..., sumvar1, sumvar2) {
groups <- enquos(...)
sumvar1 <- enquo(sumvar1)
sumvar2 <- enquo(sumvar2)
result <- data %>%
group_by(!!!groups) %>%
summarise(sum1 = sum(!!sumvar1, !!sumvar2))
return(result)
}
summarizefunction(df, col1, col2, sumvar1 = col4, sumvar2 = col5)
您可以使用 enquo
关键字来包装引号参数,以防止它们被立即计算。您可以使用 !!
(称为 bang bang)运算符取消对参数的引用。我认为这是最灵活和可重用的解决方案,即使您必须编写一些更多的初始代码。
您也可以在这些情况下使用 purrr::partial
:
library(purrr)
summarize45 <- partial(summarize, sum1 = sum(col4, col5))
result1b <- df %>%
group_by(col1, col2) %>%
summarize45()
identical(result1, result1b)
# [1] TRUE
或更进一步:
gb_df <- partial(group_by, df)
result1c <- gb_df(col1, col2) %>% summarize45()
identical(result1, result1c)
# [1] TRUE