自定义R分组函数filter报错:多分组变量过滤失效问题排查
问题排查与解决:多分组变量过滤缺失值报错
问题重现
自定义函数adsl_summ尝试对tidyCDISC包的adsl数据集,按TRT01PN和SITEID分组后统计数值列,但使用filter(if_all(all_of(group), ~ !is.na(.)))过滤分组变量缺失值时,触发"TRT01PN/SITEID不存在"的报错。
典型函数代码:
library(tidyverse) library(tidyCDISC) adsl_summ <- function(data, group, vars) { data %>% filter(if_all(all_of(group), ~ !is.na(.))) %>% group_by(across(all_of(group))) %>% summarise(across(all_of(vars), list(n = ~n(), mean = ~mean(.), sd = ~sd(.)), .names = "{.col}_{.fn}")) } # 调用时报错 adsl_summ(adsl, group = c(TRT01PN, SITEID), vars = c(AGE, TRTDURD, AVGDD))
报错原因
- 参数传递类型错误:调用函数时直接传入未引号的变量名(如
c(TRT01PN, SITEID)),R会尝试寻找全局环境中名为TRT01PN的对象,而非将其识别为数据框的列名,导致变量不存在的报错。 - tidy eval作用域兼容问题:部分旧版本dplyr中,
if_all对all_of的解析存在作用域偏差,无法正确识别函数参数中的字符向量型列名。
解决方法
方法1:支持未引号变量名输入
使用rlang包的符号转换工具,将未引号的变量名转为字符向量,确保if_all能正确识别列名:
adsl_summ <- function(data, group, vars) { # 转换未引号变量名为字符向量 group_chr <- rlang::ensyms(group) %>% purrr::map_chr(rlang::as_string) vars_chr <- rlang::ensyms(vars) %>% purrr::map_chr(rlang::as_string) data %>% filter(if_all(all_of(group_chr), ~ !is.na(.))) %>% group_by(across(all_of(group_chr))) %>% summarise(across(all_of(vars_chr), list(n = ~n(), mean = ~mean(.), sd = ~sd(.)), .names = "{.col}_{.fn}")) } # 调用示例(支持未引号变量名) adsl_summ(adsl, group = c(TRT01PN, SITEID), vars = c(AGE, TRTDURD, AVGDD))
方法2:改用字符向量输入+替代过滤逻辑
如果习惯传入字符型列名,可改用rowSums配合across实现过滤,避免if_all的作用域问题:
adsl_summ <- function(data, group, vars) { data %>% # 过滤所有分组变量无缺失值的行 filter(rowSums(is.na(across(all_of(group)))) == 0) %>% group_by(across(all_of(group))) %>% summarise(across(all_of(vars), list(n = ~n(), mean = ~mean(.), sd = ~sd(.)), .names = "{.col}_{.fn}")) } # 调用示例(传入字符向量) adsl_summ(adsl, group = c("TRT01PN", "SITEID"), vars = c("AGE", "TRTDURD", "AVGDD"))
额外排查建议
- 检查dplyr版本:建议升级到1.0.0及以上版本,新版本对
if_all、all_of等tidy eval工具的支持更稳定。 - 单独测试过滤逻辑:在函数外运行
adsl %>% filter(if_all(c("TRT01PN", "SITEID"), ~!is.na(.))),验证逻辑是否本身可行,缩小问题范围。
内容的提问来源于stack exchange,提问作者jkatam
相关产品推荐
相关产品推荐

