【问题标题】:How to refer to a variable inside a function with tidy eval after renaming it?重命名后如何使用整洁的 eval 引用函数内的变量?
【发布时间】:2021-08-15 22:11:38
【问题描述】:

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

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

【问题讨论】:

    标签: r tidyverse tidyeval


    【解决方案1】:

    同时使用 {{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
    
    

    【讨论】:

    • 这很有趣。我认为我必须将新变量名称作为字符串传递,因为当它第一次在 rename 行中进行评估时,它不是“数据变量”。我也不知道:= 可以用于左侧没有字符串的任何东西。 dplyr.tidyverse.org/articles/programming.html不太清楚
    【解决方案2】:

    为了让您的函数正常工作,您首先必须化解您的自定义参数名称。为此,我们可以使用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
    

    【讨论】:

      【解决方案3】:

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

      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
      

      【讨论】:

      • 感谢您的解释!我应该提到我将变量名作为字符串传递,因此是单个花括号。这段代码似乎可以工作,因为rename 秘密接受字符串以及数据变量?
      猜你喜欢
      • 2018-05-31
      • 2018-01-10
      • 1970-01-01
      • 2023-04-05
      • 2021-04-09
      • 1970-01-01
      • 2020-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多