R函数支持单个列名但无法通过map()处理列名列表求助
问题根源
- 你当前的
col_list存的是列的实际数据(向量),但函数里用{{ col_name }}是期望接收列名的符号/字符串,不是具体数值向量。把整个列向量传进去后,filter({{ col_name }} !=1)会用整个向量和1做比较,过滤后分组时,mutate里再用原向量计算就会出现长度不匹配的错误(分组后每组行数和原向量长度10不一致)。 - 函数直接修改全局的
df属于不良编程习惯,容易引发意外问题,应该把df作为参数传入函数,保持函数独立性。
修正方案
版本1:字符串列名 + .data代词
修改函数,让它接收字符串形式的列名,同时传入df参数:
library(tidyverse) set.seed(12) df <- tibble(col1 = sample(c("a", "b", "c"), 10, replace = TRUE), col2 = sample(1:4, 10, replace = TRUE), col3 = sample(1:4, 10, replace = TRUE)) my_function <- function(df, col_name) { df %>% filter(.data[[col_name]] != 1) %>% group_by(Levels = fct_relevel(factor(col1), "c", "b", "a")) %>% mutate(col4 = 5 - .data[[col_name]]) %>% summarise(Score = mean(col4)) } # 列名存为字符串列表 col_list <- c("col2", "col3") # 用map调用函数 map(col_list, ~my_function(df, .x))
版本2:符号列名 + {{}}语法
如果习惯用符号传递列名,可以把列名转为符号列表后调用:
my_function <- function(df, col_name) { df %>% filter({{ col_name }} != 1) %>% group_by(Levels = fct_relevel(factor(col1), "c", "b", "a")) %>% mutate(col4 = 5 - {{ col_name }}) %>% summarise(Score = mean(col4)) } # 用syms把字符串转成符号列表 col_list <- syms(c("col2", "col3")) # 调用函数 map(col_list, ~my_function(df, !!.x))
补充说明
- 把
df作为参数传入函数,避免依赖全局变量,让函数更通用。 - 分组时直接重命名为
Levels,省去后续rename步骤,代码更简洁。 .data[[col_name]]是tidyverse中安全引用字符串列名的方式,{{}}则是处理符号参数的“注入”语法,两者都能解决你遇到的求值问题。
内容的提问来源于stack exchange,提问作者dalexco
相关产品推荐
相关产品推荐

