【问题标题】:Supplying multiple groups of variables to a function for dplyr arguments in the body为主体中 dplyr 参数的函数提供多组变量
【发布时间】:2018-10-05 07:45:47
【问题描述】:

这是数据:

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
  )

还有我想使用的向量:

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 和 3rd & 4th 向量相同,但请假设它们不同并将它们保留为不同的向量。

现在我想创建一个通用函数,我可以在其中获取数据和这些向量以获得结果。

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)
}

问题是向函数提供多个变量的多个向量以用作主体中的 dplyr 参数。我尝试查看http://dplyr.tidyverse.org/articles/programming.html,但无法解决上述问题。

【问题讨论】:

    标签: r dplyr purrr rlang tidyeval


    【解决方案1】:

    group_by 不能将 groupby_vars... 字符串作为输入。您需要使用 rlang::syms() 将字符串向量转换为变量,然后使用 !!! 取消引用它们,以便可以在 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
    

    另一种方法:在外部使用parse_exprs 解析字符串向量,然后在函数内部取消引用它们。另见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                      
    

    reprex package (v0.2.0) 于 2018 年 4 月 24 日创建。

    【讨论】:

    • 很高兴知道替代解决方案。我想,第一个解决方案会比第二个解决方案更加用户友好,因为用户不必在函数调用期间显式指定 parse_exprs,这要归功于 syms,除非我遗漏了什么。
    • 第二种情况可能对这种情况有所帮助stackoverflow.com/questions/49469982/…
    • 内容丰富!你能推荐一个很好的资源或教程来学习这些 rlang 函数,最好是用更简单易懂的例子吗?
    猜你喜欢
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 2019-03-20
    • 1970-01-01
    • 1970-01-01
    • 2016-07-17
    • 2022-01-20
    • 1970-01-01
    相关资源
    最近更新 更多