将带有参数的函数传递给r

时间:2018-10-25 00:35:35

标签: r function rlang

在将某些内容传递给R中的函数时,我很难理解所有的细微差别。rlang包及其使用方法使我感到困惑。在何时使用所有各种rlang :: sym或相关功能方面找不到很好的指南。

无论如何,我正在尝试制作一个允许传入用户定义的函数和相关参数的函数。例如均值,分位数等。我希望user_metric始终用引号引起来,并且它还必须能够包含各种参数本身,例如na.rm = TRUE等。有人可以告诉我这是怎么工作的,所以无论我要传递'mean'还是'mean(。,na.rm = TRUE)'都可以?

library(tidyverse)
group_by_metrics=function(data, group_col, user_metric){

metrics = data %>% group_by(!!rlang:sym(group_col)) %>% summarise_all(.funs = funs(!!rlang::syms(user_metric))

return(metrics)
}

group_by_metrics(data=mtcars, group_col='vs', user_metric='mean')
group_by_metrics(data=mtcars, group_col='vs', user_metric='mean(., na.rm = TRUE)'
group_by_metrics(data=mtcars, group_col='vs', user_metric ='quantile(., probs=0.95, na.rm = TRUE')

1 个答案:

答案 0 :(得分:1)

您必须区分仅提供函数名称的第一种情况与有效定义lambda函数的其他情况。对于前者,可以使用match.fun通过名称查找函数。对于后者,将您的字符串转换为公式,然后使用purrr::as_mapper()来使它们成为函数。使用ensym而不是sym允许使用不带引号的参数。

group_by_metrics <- function(.data, group_col, user_metric)
{
  f <- purrr::possibly( match.fun, NULL )(user_metric)
  if( is.null(f) )
      f <- str_c( "~", user_metric ) %>% as.formula %>% as_mapper
  .data %>% group_by(!!rlang::ensym(group_col)) %>% summarize_all( f )
}

group_by_metrics( mtcars, "vs", "quantile(., probs=0.95, na.rm=TRUE)" )
#      vs   mpg   cyl  disp    hp  drat    wt  qsec    am  gear  carb
#   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1     0  21.7     8  462.  275.  4.25  5.36  18.0     1  5     6.30
# 2     1  32.9     6  237.  123   4.47  3.45  21.2     1  4.35  4   

## Using ensym instead of sym allows you to drop " for group_col
group_by_metrics( mtcars, vs, "mean" )
#      vs   mpg   cyl  disp    hp  drat    wt  qsec    am  gear  carb
#   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1     0  16.6  7.44  307. 190.   3.39  3.69  16.7 0.333  3.56  3.61
# 2     1  24.6  4.57  132.  91.4  3.86  2.61  19.3 0.5    3.86  1.79

请注意,如果您使用...分别传递其他参数,则可以避免所有这种转换:

group_by_metrics2 <- function(.data, group_col, user_metrics, ...)
{ 
  .data %>% group_by(!!rlang::ensym(group_col)) %>% 
    summarize_all( user_metrics, ... ) 
}

group_by_metrics2( mtcars, "vs", "quantile", probs=0.05, na.rm=TRUE)
# # A tibble: 2 x 11
#      vs   mpg   cyl  disp    hp  drat    wt  qsec    am  gear  carb
#   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1     0  10.4   5.7 141.  107.   2.90  2.55  14.6     0     3     2
# 2     1  18.0   4    74.1  58.5  2.97  1.58  17.8     0     3     1

在最后一个示例中,"vs周围的字符串引号quantile是可选的。