重命名后如何使用 tidy eval 引用函数内的变量?

How to refer to a variable inside a function with tidy eval after renaming it?

是否可以在使用整洁评估重命名后引用变量名?例如,我想编写一个与以下代码相同但允许在函数参数中指定新变量名称的函数:

library(tidyverse)

mtcars %>% 
  rename(cylinder = cyl) %>% 
  group_by(cylinder) %>% 
  summarize(mean_mpg = mean(mpg))

但是,我卡在 group_by 行(在下面的代码中),因为 !!varname{{ varname }} 都不能代替问号。我假设 !!varname 不起作用,因为它扩展为字符串;并且 {{ varname }} 不起作用,因为调用该函数时不存在具有新名称的列。我也看不到使用 glue 语法的方法,因为该行没有任何内容。

my_rename <- function(df, varname) {
  df %>% 
    rename("{varname}" := cyl) %>% 
    group_by(???) %>%
    summarize(mean_mpg = mean(mpg))
}

运行 {{varname}} 似乎都有效

my_rename <- function(df, varname) {
  df %>% 
    rename({{varname}} := cyl) %>% 
    group_by({{varname}}) %>%
    summarize(mean_mpg = mean(mpg))
}

my_rename(mtcars, cylinder)

# A tibble: 3 x 2
  cylinder mean_mpg
     <dbl>    <dbl>
1        4     26.7
2        6     19.7
3        8     15.1

为了使您的函数正常工作,您首先必须消除自定义参数名称的影响。为此,我们可以使用 ensymenquo 函数来化解用户定义的参数。之后你应该使用 bang bang (!!) 运算符取消引用它。

my_rename <- function(df, varname) {
  varname <- ensym(varname)
  
  df %>% 
    rename(!!varname := cyl) %>% 
    group_by(!!varname) %>%
    summarize(mean_mpg = mean(mpg))
}

my_rename(mtcars, cylinder)

# A tibble: 3 x 2
  cylinder mean_mpg
     <dbl>    <dbl>
1        4     26.7
2        6     19.7
3        8     15.1

这是我们使用 enquo 函数代替 ensym 的另一种方法:

my_rename <- function(df, varname) {
  varname <- enquo(varname)
  
  df %>% 
    rename(!!varname := cyl) %>% 
    group_by(!!varname) %>%
    summarize(mean_mpg = mean(mpg))
}

# A tibble: 3 x 2
  cylinder mean_mpg
     <dbl>    <dbl>
1        4     26.7
2        6     19.7
3        8     15.1

关于粘合语法,您需要 "{{ varname }}" := 而不是 "{varname}"。简单的 curly 是普通的胶水语法,它获取一个字符串 inside 一个变量。 double curly 是扩展的胶水语法,它通过 across 函数参数来查看用户键入的内容。所以正确的语法是:

my_rename <- function(df, varname) {
  df %>% 
    rename("{{ varname }}" := cyl) %>% 
    group_by({{ varname }}) %>%
    summarize(mean_mpg = mean(mpg))
}

my_rename(mtcars, cylinder)
#> # A tibble: 3 x 2
#>   cylinder mean_mpg
#>      <dbl>    <dbl>
#> 1        4     26.7
#> 2        6     19.7
#> 3        8     15.1

现在让我们用您的原始代码解压该行为:

my_rename <- function(df, varname) {
  df %>%
    rename("{varname}" := cyl)
}

my_rename(mtcars, cylinder)
#> Error: object 'cylinder' not found

这里的问题是 "{varname"} 本质上是这样做的:

cylinder
#> Error: object 'cylinder' not found

而不是这个:

rlang::quo(cylinder)
#> <quosure>
#> expr: ^cylinder
#> env:  global