按函数替换多个 `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