如何在R的dplyr嵌套函数中传递列名完成CSV数据连接?
尝试用tidyverse编写嵌套函数:
- 外层函数接收CSV文件名,读取为数据框,提取首列作为键列名后调用内层函数
- 内层函数接收两个数据框和键列名,通过
inner_join完成连接
硬编码列名时内层函数可正常运行,但外层传递变量(如df1_key)或表达式(如colnames(df1)[1])形式的列名时报错:
- 传递变量时的报错:
Error in
inner_join():
! Join columns inxmust be present in the data.
✖ Problem withdf1_key.
Runrlang::last_trace()to see where the error occurred.
- 传递表达式时的报错:
Error in
join_by():
! Expressions can't contain computed columns, and can only reference columns by name or by explicitly specifying
a side, likex$colory$col.
ℹ Expression 1 containscolnames(df1)[1].
Runrlang::last_trace()to see where the error occurred.
可复现代码:
library(tidyverse) # 创建示例CSV df1 = tibble( key = LETTERS, value = sample.int(100, 26) ) write_csv(df1, "df1.csv") df2 = tibble( key = LETTERS[1:13], value = sample.int(100, 13) ) write_csv(df2, "df2.csv") # 连接两个数据框的函数 join_dfs = function(x, y, x_key = "key", y_key = "key") { df = x |> inner_join(y, by = join_by({{ x_key }} == {{ y_key }} )) } # 硬编码列名可正常运行 df3 = join_dfs(df1, df2, "key", "key") # 加载CSV并调用join_dfs的外层函数 join_csvs = function(x, y, file) { df1 = read_csv(x) df1_key = colnames(df1)[1] print(df1_key) df2 = read_csv(y) df2_key = colnames(df2)[1] print(df2_key) df3 = join_dfs(df1, df2, df1_key, df2_key) write_csv(df3, file) } # 运行报错 join_csvs("df1.csv", "df2.csv", "df3.csv")
问题出在join_by({{ x_key }} == {{ y_key }})的用法上:{{}}(大括号插值)是用于直接引用符号形式的列名,但外层函数传递的是字符串类型的列名变量,两者不匹配。可以通过两种方式解决:
方法1:将字符串转为符号后插值
用rlang::sym()把字符串列名转为符号,再用!!(强制求值)在join_by中使用:
join_dfs = function(x, y, x_key = "key", y_key = "key") { # 把字符串转为符号 x_sym = sym(x_key) y_sym = sym(y_key) df = x |> inner_join(y, by = join_by(!!x_sym == !!y_sym)) }
方法2:使用命名向量指定连接列
如果不需要join_by的复杂逻辑,直接用inner_join的by参数传递命名向量,更简洁:
join_dfs = function(x, y, x_key = "key", y_key = "key") { # 构造命名向量:x的列名作为名字,y的列名作为值 join_cols = setNames(y_key, x_key) df = x |> inner_join(y, by = join_cols) }
修改后,运行join_csvs("df1.csv", "df2.csv", "df3.csv")即可正常完成连接并写入文件。
内容的提问来源于stack exchange,提问作者Lee Hachadoorian

