R语言中传入字符串列名至函数失效问题求助
问题
需求是从现有数据框中提取指定两列(如MAT_cat和Ndep_cat)的唯一值,通过expand.grid生成包含所有组合的新数据框cat_xy。
单行代码可正常运行:
cat_xy <- expand.grid(data.frame(unique(na.omit(obs_data1[,"MAT_cat"])), unique(na.omit(obs_data1[,"Ndep_cat"]))))
但封装为函数后,传入字符串类型的列名参数group1和group2时失效,报错来自[.data.table:
Func <- function(data, group1, group2) { cat_xy <- expand.grid(data.frame(unique(na.omit(data[,group1])), unique(na.omit(data[,group2])))) }
尝试过eval(parse)方案但不够优雅,寻求更好的解决办法。
解决方案
方案1:Base R 优雅实现(推荐)
用[[代替[来提取列,[[可以直接通过字符串名称索引数据框或data.table的列,避免[在data.table环境下的索引歧义,同时拆分步骤更清晰:
Func <- function(data, group1, group2) { # 提取并处理目标列的唯一非缺失值 col_vals1 <- unique(na.omit(data[[group1]])) col_vals2 <- unique(na.omit(data[[group2]])) # 生成全组合,同时保留原列名 expand.grid(!!group1 := col_vals1, !!group2 := col_vals2, stringsAsFactors = FALSE) }
注:!!group1 := 是利用rlang的准引用语法,将字符串参数转化为列名,让输出数据框的列名和原数据一致,避免默认的Var1/Var2。如果不需要保留原列名,也可以简化为expand.grid(col_vals1, col_vals2, stringsAsFactors = FALSE)。
方案2:Tidyverse 风格实现
如果习惯使用dplyr等tidy工具链,可以用以下方式,代码可读性更强:
library(dplyr) library(tidyr) Func <- function(data, group1, group2) { data %>% # 按字符串参数选择目标列 select(all_of(c(group1, group2))) %>% # 移除缺失值 drop_na() %>% # 提取唯一行 distinct() %>% # 生成所有列的组合 expand(!!sym(group1), !!sym(group2)) }
注:all_of()用于处理字符串形式的列名选择,!!sym()将字符串转化为符号,适配tidyverse的语法。
内容的提问来源于stack exchange,提问作者y chung
相关产品推荐
相关产品推荐

