Passing a list of arguments to a function with quasiquotation

后端 未结 2 2105
不知归路
不知归路 2020-12-06 14:36

I am trying to write a function in R that summarizes a data frame according to grouping variables. The grouping variables are given as a list and passed to group_by_at

2条回答
  •  执念已碎
    2020-12-06 15:11

    You could make use of the ellipse .... Take the following example:

    sum_fun <- function(df, sum_var, ...) {
      sum_var <- substitute(sum_var)
      grps    <- substitute(list(...))[-1L]
      return(
        df %>% 
          group_by_at(.vars = as.character(grps)) %>% 
          summarize(sum(!! sum_var))
      )
    }
    
    d %>% sum_fun(baz, foo, bar)
    

    We take the additional arguments and create a list out of them. Afterwards we use non-standard evaluation (substitute) to get the variable names and prevent R from evaluating them. Since group_by_at expects an object of type character or numeric, we simply convert the vector of names into a vector of characters and the function gets evaluated as we would expect.

    > d %>% sum_fun(baz, foo, bar)
    # A tibble: 3 x 3
    # Groups:   foo [?]
        foo   bar `sum(baz)`
             
    1     1     2          3
    2     1     3          5
    3     4     5          7
    

    If you do not want to supply grouping variables as any number of additional arguments, then you can of course use a named argument:

    sum_fun <- function(df, sum_var, grps) {
      sum_var <- enquo(sum_var)
      grps    <- as.list(substitute(grps))[-1L]
      return(
        df %>% 
          group_by_at(.vars = as.character(grps)) %>% 
          summarize(sum(!! sum_var))
      )
    }
    
    sum_fun(mtcars, sum_var = hp, grps = c(cyl, gear))
    

    The reason why I use substitute is that it makes it easy to split the expression list(cyl, gear) in its components. There might be a way to use rlang but I have not digged into that package so far.

提交回复
热议问题