I often struggle with these sorts of tidyeval issues. The code below is flexible regarding the number of grouping columns and value columns, and will work with bare names or strings. I'm not sure if this is the "best" or "intended" way to use tidyeval, but it seems to work. (Maybe @lionel can provide additional guidance.)
library(tidyverse)
# Add a second grouping variable to iris
d = iris %>% mutate(group2 = rep(LETTERS[1:3], 50))
fnc = function(data, value.vars, group.vars=NULL) {
data %>%
group_by(across({{group.vars}})) %>%
summarise(n=n(), across({{value.vars}}, mean, .names="mean_{.col}"))
}
First, show that the function works when we invoke it directly:
d %>% fnc(c(Petal.Width, Sepal.Width))
#> # A tibble: 1 x 3
#> n mean_Petal.Width mean_Sepal.Width
#> <int> <dbl> <dbl>
#> 1 150 1.20 3.06
d %>% fnc(c("Petal.Width", "Sepal.Width"))
#> # A tibble: 1 x 3
#> n mean_Petal.Width mean_Sepal.Width
#> <int> <dbl> <dbl>
#> 1 150 1.20 3.06
d %>% fnc(c(Petal.Width, Sepal.Width), Species)
#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 3 x 4
#> Species n mean_Petal.Width mean_Sepal.Width
#> <fct> <int> <dbl> <dbl>
#> 1 setosa 50 0.246 3.43
#> 2 versicolor 50 1.33 2.77
#> 3 virginica 50 2.03 2.97
d %>% fnc(c("Petal.Width", "Sepal.Width"), "Species")
#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 3 x 4
#> Species n mean_Petal.Width mean_Sepal.Width
#> <fct> <int> <dbl> <dbl>
#> 1 setosa 50 0.246 3.43
#> 2 versicolor 50 1.33 2.77
#> 3 virginica 50 2.03 2.97
d %>% fnc(c(Petal.Width, Sepal.Width), c(Species, group2))
#> `summarise()` regrouping output by 'Species' (override with `.groups` argument)
#> # A tibble: 9 x 5
#> # Groups: Species [3]
#> Species group2 n mean_Petal.Width mean_Sepal.Width
#> <fct> <chr> <int> <dbl> <dbl>
#> 1 setosa A 17 0.229 3.47
#> 2 setosa B 17 0.247 3.45
#> 3 setosa C 16 0.262 3.36
#> 4 versicolor A 17 1.29 2.68
#> 5 versicolor B 16 1.34 2.91
#> 6 versicolor C 17 1.35 2.74
#> 7 virginica A 16 2.07 2.98
#> 8 virginica B 17 2.09 3.02
#> 9 virginica C 17 1.92 2.92
d %>% fnc(c("Petal.Width", "Sepal.Width"), c("Species", "group2"))
#> `summarise()` regrouping output by 'Species' (override with `.groups` argument)
#> # A tibble: 9 x 5
#> # Groups: Species [3]
#> Species group2 n mean_Petal.Width mean_Sepal.Width
#> <fct> <chr> <int> <dbl> <dbl>
#> 1 setosa A 17 0.229 3.47
#> 2 setosa B 17 0.247 3.45
#> 3 setosa C 16 0.262 3.36
#> 4 versicolor A 17 1.29 2.68
#> 5 versicolor B 16 1.34 2.91
#> 6 versicolor C 17 1.35 2.74
#> 7 virginica A 16 2.07 2.98
#> 8 virginica B 17 2.09 3.02
#> 9 virginica C 17 1.92 2.92
Now try mapping over combinations of grouping columns:
quos(NULL, Species, group2, c(Species, group2)) %>%
map(~fnc(d, c(Petal.Width, Sepal.Width), !!.x))
#> `summarise()` ungrouping output (override with `.groups` argument)
#> `summarise()` ungrouping output (override with `.groups` argument)
#> `summarise()` regrouping output by 'Species' (override with `.groups` argument)
#> [[1]]
#> # A tibble: 1 x 3
#> n mean_Petal.Width mean_Sepal.Width
#> <int> <dbl> <dbl>
#> 1 150 1.20 3.06
#>
#> [[2]]
#> # A tibble: 3 x 4
#> Species n mean_Petal.Width mean_Sepal.Width
#> <fct> <int> <dbl> <dbl>
#> 1 setosa 50 0.246 3.43
#> 2 versicolor 50 1.33 2.77
#> 3 virginica 50 2.03 2.97
#>
#> [[3]]
#> # A tibble: 3 x 4
#> group2 n mean_Petal.Width mean_Sepal.Width
#> <chr> <int> <dbl> <dbl>
#> 1 A 50 1.18 3.04
#> 2 B 50 1.22 3.13
#> 3 C 50 1.20 3.00
#>
#> [[4]]
#> # A tibble: 9 x 5
#> # Groups: Species [3]
#> Species group2 n mean_Petal.Width mean_Sepal.Width
#> <fct> <chr> <int> <dbl> <dbl>
#> 1 setosa A 17 0.229 3.47
#> 2 setosa B 17 0.247 3.45
#> 3 setosa C 16 0.262 3.36
#> 4 versicolor A 17 1.29 2.68
#> 5 versicolor B 16 1.34 2.91
#> 6 versicolor C 17 1.35 2.74
#> 7 virginica A 16 2.07 2.98
#> 8 virginica B 17 2.09 3.02
#> 9 virginica C 17 1.92 2.92
# Can also use "list" here instead of "quos"
quos(NULL, "Species", "group2", c("Species", "group2")) %>%
map(~fnc(d, c(Petal.Width, Sepal.Width), !!.x))
#> `summarise()` ungrouping output (override with `.groups` argument)
#> `summarise()` ungrouping output (override with `.groups` argument)
#> `summarise()` regrouping output by 'Species' (override with `.groups` argument)
#> [[1]]
#> # A tibble: 1 x 3
#> n mean_Petal.Width mean_Sepal.Width
#> <int> <dbl> <dbl>
#> 1 150 1.20 3.06
#>
#> [[2]]
#> # A tibble: 3 x 4
#> Species n mean_Petal.Width mean_Sepal.Width
#> <fct> <int> <dbl> <dbl>
#> 1 setosa 50 0.246 3.43
#> 2 versicolor 50 1.33 2.77
#> 3 virginica 50 2.03 2.97
#>
#> [[3]]
#> # A tibble: 3 x 4
#> group2 n mean_Petal.Width mean_Sepal.Width
#> <chr> <int> <dbl> <dbl>
#> 1 A 50 1.18 3.04
#> 2 B 50 1.22 3.13
#> 3 C 50 1.20 3.00
#>
#> [[4]]
#> # A tibble: 9 x 5
#> # Groups: Species [3]
#> Species group2 n mean_Petal.Width mean_Sepal.Width
#> <fct> <chr> <int> <dbl> <dbl>
#> 1 setosa A 17 0.229 3.47
#> 2 setosa B 17 0.247 3.45
#> 3 setosa C 16 0.262 3.36
#> 4 versicolor A 17 1.29 2.68
#> 5 versicolor B 16 1.34 2.91
#> 6 versicolor C 17 1.35 2.74
#> 7 virginica A 16 2.07 2.98
#> 8 virginica B 17 2.09 3.02
#> 9 virginica C 17 1.92 2.92
You can also map over group-value pairs as in your example:
vars <- names(d[1:2])
groupvars <- c("Species", "group2")
analysis_list <- crossing(groupvars, vars)
analysis_list %>% pmap(~fnc(d, .y, .x))