tidy evaluation作用域是否有限制?如何在mutate中全程使用它?
问题分析与解决方案
你的问题出在**enquo()的使用场景和传入参数的类型不匹配上:你调用函数时传的是字符串(比如"mpg"),但enquo()是用来捕获裸变量表达式**(比如直接写mpg)的,所以它会把"mpg"当成字符串字面量,而不是指向数据框列的符号。这就导致在mutate()里执行cor(!!col1, !!col2)时,实际上是把两个字符串传给了cor(),自然会报'x' must be numeric的错误。
下面是两种纯tidy evaluation的解决方案,分别适配不同的参数传入方式:
方案1:支持字符串参数(匹配你的调用习惯)
使用ensym()(dplyr 0.7.0及以上版本支持)来将字符串转换为列名符号,它会自动处理字符串输入:
library(dplyr) library(tibble) myCor <- function(col1, col2) { # 将字符串参数转换为列名符号 col1_sym <- ensym(col1) col2_sym <- ensym(col2) mtcars %>% rownames_to_column("vehicle") %>% select(vehicle, !!col1_sym, !!col2_sym) %>% mutate(correlation = cor(!!col1_sym, !!col2_sym)) } # 调用(和你原来的方式一致) myCor("mpg", "disp")
运行后就能得到预期结果,而且全程使用tidy eval语法,避免了eval(parse())这种不安全的写法。
方案2:同时支持裸变量和字符串参数
ensym()的优势在于它同时兼容裸变量和字符串输入,所以上面的函数也可以直接用裸变量调用:
myCor(mpg, disp) # 同样能正常输出结果
为什么原来的enquo()不行?
当你传入"mpg"时,enquo(col1)捕获的是字符串字面量"mpg",而不是指向mtcars$mpg的符号。此时!!col1展开后就是字符串"mpg",cor("mpg", "disp")当然会报错——因为cor()需要数值向量,而不是字符串。
内容的提问来源于stack exchange,提问作者Megatron
相关产品推荐
相关产品推荐

