如何在自定义函数中使用环境变量执行dplyr连接操作?
在自定义函数中使用tidy eval实现dplyr连接的正确方式
你碰到的这个问题很典型——问题出在left_join()的by参数对输入的要求和你用{{}}传递的内容不匹配。
为什么原来的写法会报错?
{{ }}(即"curly-curly"操作符)是tidy eval里用来捕获表达式的工具,它主要在dplyr的核心动词(比如summarise、mutate)里工作,这些动词会把捕获到的表达式当成列引用处理。但left_join()的by参数需要的是列名的字符串(或者命名字符向量),它不会把{{ joincol }}解析成列名,反而会把它当成一个普通的对象去查找,所以才会出现“object 'fooname' not found”的错误。
正确的实现方式
这里有两种靠谱的写法,你可以根据需求选择:
方法1:针对裸变量名的场景
用ensym()把传入的裸参数转换成符号,再用as_string()转成字符串:
library(dplyr) library(tibble) # 你的测试数据表 foobar <- tribble( ~fooname, ~value, "setosa", 20, "versicolor", 30, "virginica", 10 ) # 修正后的自定义函数 foobarjoin <- function(table, joincol){ # 把裸变量名转换成字符串 join_col_str <- as_string(ensym(joincol)) iris %>% left_join(table, by = c("Species" = join_col_str)) } # 调用测试,现在可以正常运行了 foobarjoin(table = foobar, joincol = fooname)
方法2:同时支持裸变量名和字符串输入
如果希望函数更灵活,既支持joincol = fooname也支持joincol = "fooname",可以用rlang::as_name()配合{{}}:
foobarjoin <- function(table, joincol){ # 自动处理裸变量或字符串输入,转为列名字符串 join_col_str <- rlang::as_name({{ joincol }}) iris %>% left_join(table, by = c("Species" = join_col_str)) } # 两种调用方式都能正常工作 foobarjoin(table = foobar, joincol = fooname) foobarjoin(table = foobar, joincol = "fooname")
核心逻辑总结
dplyr的连接函数的by参数不支持直接用{{}}来传递列名,你需要先把裸的列名参数转换成字符串,再传给by参数。上面两种方法都是利用tidy eval工具把输入的列名表达式转换成字符串,适配left_join()的参数要求。
内容的提问来源于stack exchange,提问作者RDavey
相关产品推荐
相关产品推荐

