dplyr mutate中需使用哪个rlang函数对glue生成的变量名字符串求值?
问题说明
需要编写一个可直接在dplyr::mutate()中调用的自定义函数:传入变量名后,函数自动提取传入变量名的特定模式,基于该模式拼接生成新的变量名,初始实现代码如下:
library(rlang) library(dplyr) library(stringr) library(glue) myfun <- function(var) { y <- str_remove(ensym(var), "^.*\\.") other_var <- glue("Petal.{y}") if_else(var > 6 | other_var > 3, 1, 0) # 此处需要对other_var应用哪个rlang函数? }
核心待解决问题:如何通过rlang工具,让拼接生成的新变量名other_var在数据框上下文中完成求值,使得执行如下调用时,函数可以正确读取iris$Sepal.Length和iris$Petal.Length的列数据:
mutate(iris, test = myfun(Sepal.Length))
目前已有可满足即时需求的实现,但该写法需要手动传入数据框参数,不符合dplyr的常规调用习惯,应该存在更优雅的rlang原生实现:
myfun <- function(df, x) { y <- str_remove(ensym(x), "^.*\\.") other_var <- glue("Petal.{y}") if_else(x > 6 | df[[other_var]] > 3, 0, 1) } mutate(iris, test = myfun(iris, Sepal.Length))
实现方案
通过rlang的元编程工具即可实现无额外传参的版本,核心逻辑是将拼接得到的变量名字符串转为符号后注入求值上下文,代码如下:
myfun <- function(var) { # 捕获传入的未求值变量,转为字符串做文本处理 input_var <- ensym(var) var_suffix <- str_remove(as_string(input_var), "^.*\\.") # 拼接目标变量名,转为rlang符号 target_var <- sym(glue("Petal.{var_suffix}")) # {{ }} 用于求值用户传入的原始变量,!! 用于注入我们生成的目标变量符号 if_else({{ var }} > 6 | !!target_var > 3, 1, 0) }
关键逻辑说明:
ensym()用于捕获用户传入的未赋值变量名,避免R提前在全局环境中查找变量sym()可以把普通字符串转为R可识别的变量符号,是处理动态生成变量名的核心函数{{ }}(拥抱运算符)是dplyr/rlang提供的快捷写法,用于在数据掩码中正确求值用户传入的函数参数!!(注入运算符)可以把手动生成的符号插入到待求值的表达式中,让mutate自动在当前操作的数据框中查找对应列,不需要手动传入数据框参数
修改后直接调用最初期望的写法即可正常运行:
mutate(iris, test = myfun(Sepal.Length))
内容的提问来源于stack exchange,提问作者Phil
相关产品推荐
相关产品推荐

