问题
Here is the data:
library(tidyverse)
data <- tibble::tribble(
~var1, ~var2, ~var3, ~var4, ~var5,
"a", "d", "g", "hello", 1L,
"a", "d", "h", "hello", 2L,
"b", "e", "h", "k", 4L,
"b", "e", "h", "k", 7L,
"c", "f", "i", "hello", 3L,
"c", "f", "i", "hello", 4L
)
and the vectors, I want to use:
filter_var <- c("hello")
groupby_vars1 <- c("var1", "var2", "var3")
groupby_vars2 <- c("var1", "var2")
joinby_vars1 <- c("var1", "var2")
joinby_vars2 <- c("var1", "var2", "var3")
2nd & 5th, and 3rd & 4th vectors are same, but please assume they are different and retain them as different vectors.
Now I want to create a generic function where I can take data and these vectors to get the results.
my_fun <- function(data, filter_var, groupby_vars1,groupby_vars2, joinby_vars1, joinby_vars2) {
data2 <- data %>% filter(var4 == filter_var)
data3 <- data2 %>%
group_by(groupby_vars1) %>%
summarise(var6 = sum(var5))
data4 <- data3 %>%
ungroup() %>%
group_by(groupby_vars2) %>%
summarise(avg = mean(var6,na.rm = T))
data5 <- data3 %>% left_join(data4, by = joinby_vars1)
data6 <- data %>% left_join(data5, by = joinby_vars2)
}
The problem is of supplying multiple vectors of multiple variables to a function to be used as dplyr arguments in the body. I tried looking into the http://dplyr.tidyverse.org/articles/programming.html, but could not solve the above problem.
回答1:
group_by
cannot take groupby_vars...
strings as input. You need to use rlang::syms()
to turn string vector into variables then use !!!
to unquote them so that they can be evaluated inside group_by
library(tidyverse)
library(rlang)
data <- tibble::tribble(
~var1, ~var2, ~var3, ~var4, ~var5,
"a", "d", "g", "hello", 1L,
"a", "d", "h", "hello", 2L,
"b", "e", "h", "k", 4L,
"b", "e", "h", "k", 7L,
"c", "f", "i", "hello", 3L,
"c", "f", "i", "hello", 4L
)
filter_var <- c("hello")
groupby_vars1 <- c("var1", "var2", "var3")
groupby_vars2 <- c("var1", "var2")
joinby_vars1 <- c("var1", "var2")
joinby_vars2 <- c("var1", "var2", "var3")
my_fun <- function(data, filter_var,
groupby_vars1, groupby_vars2,
joinby_vars1, joinby_vars2) {
groupby_vars1 <- syms(groupby_vars1)
groupby_vars2 <- syms(groupby_vars2)
data2 <- data %>%
filter(var4 == filter_var)
data3 <- data2 %>%
group_by(!!! groupby_vars1) %>%
summarise(var6 = sum(var5))
data4 <- data3 %>%
ungroup() %>%
group_by(!!! groupby_vars2) %>%
summarise(avg = mean(var6, na.rm = TRUE))
data5 <- data3 %>%
left_join(data4, by = joinby_vars1)
data6 <- data %>%
left_join(data5, by = joinby_vars2)
return(data6)
}
my_fun(data, filter_var,
groupby_vars1, groupby_vars2,
joinby_vars1, joinby_vars2)
#> # A tibble: 6 x 7
#> var1 var2 var3 var4 var5 var6 avg
#> <chr> <chr> <chr> <chr> <int> <int> <dbl>
#> 1 a d g hello 1 1 1.5
#> 2 a d h hello 2 2 1.5
#> 3 b e h k 4 NA NA
#> 4 b e h k 7 NA NA
#> 5 c f i hello 3 7 7
#> 6 c f i hello 4 7 7
Another way to do it: parse the string vector using parse_exprs
outside then unquote them inside the function. See also this
my_fun2 <- function(data, filter_var,
groupby_vars1, groupby_vars2,
joinby_vars1, joinby_vars2) {
data2 <- data %>%
filter(var4 == filter_var)
data3 <- data2 %>%
group_by(!!! groupby_vars1) %>%
summarise(var6 = sum(var5))
data4 <- data3 %>%
ungroup() %>%
group_by(!!! groupby_vars2) %>%
summarise(avg = mean(var6, na.rm = TRUE))
data5 <- data3 %>%
left_join(data4, by = joinby_vars1)
data6 <- data %>%
left_join(data5, by = joinby_vars2)
return(data6)
}
my_fun2(data, filter_var,
parse_exprs(groupby_vars1), parse_exprs(groupby_vars2),
joinby_vars1, joinby_vars2)
identical(my_fun(data, filter_var,
groupby_vars1, groupby_vars2,
joinby_vars1, joinby_vars2),
my_fun2(data, filter_var,
parse_exprs(groupby_vars1), parse_exprs(groupby_vars2),
joinby_vars1, joinby_vars2))
[1] TRUE
Created on 2018-04-24 by the reprex package (v0.2.0).
来源:https://stackoverflow.com/questions/50011988/supplying-multiple-groups-of-variables-to-a-function-for-dplyr-arguments-in-the