如何在tidy管道中传递外部列名变量?原特性已弃用
问题解决:字符串列名传入tidyverse函数的透视错误
问题描述
需要处理多个Excel工作表,每个表的第一列标题不同,因此需要将列名字符串作为外部变量传入函数,在函数的tidy管道中执行透视操作。但调用时触发错误,提示列不存在,尝试all_of()和deparse(substitute)方法均未解决。
错误代码与报错信息
错误代码
totals <- tibble::tribble( ~Units, ~NACE, ~"1990", ~"1991", ~"1992", ~"1993", ~"1994", ~"1995", ~"1996", ~"1997", ~"1998", "Imports", 0, 4155, 5145, 7355, 6155, 4715, 4155, 4155, 4155, 4155, "Exports", 0, 3952, 3952, 3952, 3952, 3952, 3952, 3952, 3952, 3952, "X", 14, 99598, 99598, 99598, 99598, 99598, 99598, 99598, 99598, 99598, "Y", 16, 6260, 6260, 6260, 6260, 6260, 6260, 6260, 6260, 6260, "Z", 8, 36583, 36583, 36583, 36583, 36583, 36583, 36583, 36583, 36583, ) # ---- reshape data ---- reshape_data <- function(data, colname){ main <- totals %>% select(!NACE) new_col <- main %>% pivot_longer(!{{colname}}, names_to = "Year", values_to = "Total Supply") %>% rename(`Total.Units` = {{colname}}) } data <- (totals, "Units") # 或 colname = "Units",两种方式均无效
报错信息
Error in `pivot_longer()`: ! Can't subset columns that don't exist. ✖ Column `"Units"` doesn't exist.
问题原因
- 函数内部硬编码使用了
totals数据框,而非传入的data参数,导致传入的工作表数据未被使用。 - 传入的是字符串形式的列名,但使用了针对裸变量名的
{{}}语法,{{}}会将字符串解析为带引号的列名(如"Units"),而数据框中不存在带引号的列,因此报错。 - 函数调用语法错误,未正确调用
reshape_data函数。
解决方案
- 函数内部使用传入的
data参数替代硬编码的totals。 - 针对字符串列名,使用
all_of()函数在tidyselect场景下(如pivot_longer、select、rename)正确引用列。 - 修正函数调用语法,正确传入参数。
完整修正代码
totals <- tibble::tribble( ~Units, ~NACE, ~"1990", ~"1991", ~"1992", ~"1993", ~"1994", ~"1995", ~"1996", ~"1997", ~"1998", "Imports", 0, 4155, 5145, 7355, 6155, 4715, 4155, 4155, 4155, 4155, "Exports", 0, 3952, 3952, 3952, 3952, 3952, 3952, 3952, 3952, 3952, "X", 14, 99598, 99598, 99598, 99598, 99598, 99598, 99598, 99598, 99598, "Y", 16, 6260, 6260, 6260, 6260, 6260, 6260, 6260, 6260, 6260, "Z", 8, 36583, 36583, 36583, 36583, 36583, 36583, 36583, 36583, 36583, ) # 修正后的函数 reshape_data <- function(data, colname){ # 使用传入的data参数,而非硬编码的totals main <- data %>% select(!NACE) new_col <- main %>% # 用all_of()处理字符串列名 pivot_longer(!all_of(colname), names_to = "Year", values_to = "Total Supply") %>% # rename中同样用all_of()引用字符串列名 rename(Total.Units = all_of(colname)) # 返回处理后的数据框 return(new_col) } # 正确调用函数 data <- reshape_data(totals, "Units")
补充说明
如果需要同时支持裸变量名(如传入Units而非"Units")和字符串列名,可以在函数内部将列名统一转换为符号:
reshape_data <- function(data, colname){ # 将输入转换为符号,兼容两种传参方式 col_sym <- rlang::ensym(colname) main <- data %>% select(!NACE) new_col <- main %>% pivot_longer(!{{col_sym}}, names_to = "Year", values_to = "Total Supply") %>% rename(Total.Units = {{col_sym}}) return(new_col) } # 两种调用方式都有效 data1 <- reshape_data(totals, Units) data2 <- reshape_data(totals, "Units")
内容的提问来源于stack exchange,提问作者Magnetar
相关产品推荐
相关产品推荐

