使用purrr::map批量执行函数时出现non-numeric argument错误求助
用map批量执行自定义统计函数时出现non-numeric参数错误
我需要用map函数对指定列批量生成汇总统计,单独调用自定义函数正常,但批量执行时触发non-numeric argument to mathematical function错误,具体代码和报错如下:
自定义统计函数
sumtab_ce_dt_ow_test <- function (df, depvar, treatvar) { require(dplyr, kableExtra) df %>% dplyr::ungroup() %>% mutate({{depvar}} := as.numeric({{depvar}})) %>% dplyr::filter(!is.na({{depvar}})) %>% group_by({{treatvar}}) %>% dplyr::summarize( N = n(), Med = round(median({{depvar}}, na.rm = T), 2) ) %>% arrange({{treatvar}}) }
示例数据
my_tibble <- tibble( rownumber = 1:100, a = sample(1:5, 100, replace = TRUE), b = sample(1:5, 100, replace = TRUE), c = sample(1:5, 100, replace = TRUE), phase = sample(c("before", "after"), 100, replace = TRUE), ) %>% mutate( across( c(a, b, c), factor, levels = 1:5, labels = c("Strongly agree", "Agree", "Neutral", "Disagree", "Strongly disagree") ) )
单独调用函数正常
my_tibble %>% sumtab_ce_dt_ow_test(depvar = a, treatvar = phase) my_tibble %>% sumtab_ce_dt_ow_test(depvar = b, treatvar = phase) my_tibble %>% sumtab_ce_dt_ow_test(depvar = c, treatvar = phase)
批量map调用报错代码
library(rlang) response_texts <- c("Name 1", "name 2", "blah") depvars <- c("a", "b", "c") my_tibble <- my_tibble %>% mutate(across(all_of(depvars), ~ as.numeric(.x))) results <- map2_df(depvars, response_texts, function(depvar, response_text) { depvar <- enquo(depvar) my_tibble %>% sumtab_ce_dt_ow_test(depvar = !!depvar, treatvar = phase) %>% mutate(response = response_text) })
报错信息
Error in `dplyr::summarize()`: ! Problem while computing `Med = round(median("a", na.rm = T), 2)`. ℹ The error occurred in group 1: phase = "after". Caused by error in `round()`: ! non-numeric argument to mathematical function Backtrace: 1. purrr::map2_df(...) 10. dplyr:::summarise.grouped_df(...) 11. dplyr:::summarise_cols(.data, dplyr_quosures(...), caller_env = caller_env()) 13. dplyr:::map(quosures, summarise_eval_one, mask = mask) 14. base::lapply(.x, .f, ...) 15. dplyr (local) FUN(X[[i]], ...) 16. mask$eval_all_summarise(quo) Called from: signal_abort(cnd, .file) Warning message: Problem while computing `a = as.numeric("a")`. ℹ NAs introduced by coercion
问题原因与解决办法
- 核心问题:
enquo(depvar)会把传入的字符串(比如"a")转换成引用字符串本身的表达式,而非引用数据框中的列。函数中{{depvar}}实际调用的是字符串值"a",导致as.numeric("a")产生NA,后续median("a")触发非数值参数错误。 - 解决方法:直接使用
.data代词或sym()+!!解析字符串列名,无需enquo:
修正后的批量调用代码
library(rlang) library(purrr) response_texts <- c("Name 1", "name 2", "blah") depvars <- c("a", "b", "c") my_tibble <- my_tibble %>% mutate(across(all_of(depvars), ~ as.numeric(.x))) # 方法1:使用.data代词 results <- map2_df(depvars, response_texts, function(depvar, response_text) { my_tibble %>% sumtab_ce_dt_ow_test(depvar = .data[[depvar]], treatvar = phase) %>% mutate(response = response_text) }) # 方法2:使用sym转换为符号后解引用 # results <- map2_df(depvars, response_texts, function(depvar, response_text) { # depvar_sym <- sym(depvar) # my_tibble %>% # sumtab_ce_dt_ow_test(depvar = !!depvar_sym, treatvar = phase) %>% # mutate(response = response_text) # })
可选:修改函数兼容两种输入方式
如果希望函数同时支持裸列名和字符串列名,可调整函数代码:
sumtab_ce_dt_ow_test <- function (df, depvar, treatvar) { require(dplyr, kableExtra) depvar <- enquo(depvar) # 若传入字符串,转换为对应列的符号 if (is.character(depvar[[2]])) { depvar <- sym(depvar[[2]]) } treatvar <- enquo(treatvar) df %>% dplyr::ungroup() %>% mutate(!!depvar := as.numeric(!!depvar)) %>% dplyr::filter(!is.na(!!depvar)) %>% group_by(!!treatvar) %>% dplyr::summarize( N = n(), Med = round(median(!!depvar, na.rm = T), 2) ) %>% arrange(!!treatvar) }
内容的提问来源于stack exchange,提问作者daaronr
相关产品推荐
相关产品推荐

