使用dplyr的summarise()和across()计算变异系数时出错
错误原因
你写的(sd/mean)*100是试图将两个函数对象sd()和mean()做除法运算,这显然不符合语法要求——across的第二个参数需要是针对单列数据的函数,而非直接用函数名做算术操作。同时,在同一个summarise()调用里,后续的across无法引用前面生成的_mean和_sd列,因为across始终是对分组后的原始列进行操作。
解决方案
方案1:单across一次性计算所有统计量
最简洁的方式,对每列同时计算均值、标准差、变异系数,避免跨步骤引用问题:
df2 <- df %>% group_by(group) %>% summarise( across(where(is.numeric), list( mean = ~mean(., na.rm = TRUE), sd = ~sd(., na.rm = TRUE), cv = ~100 * (sd(., na.rm = TRUE)/mean(., na.rm = TRUE)) ), .names = "{col}_{fn}") )
这里用list()封装三个匿名函数,.代表当前处理的列,.names参数自动生成带后缀的列名。
方案2:先算均值/标准差,再用mutate生成CV
如果偏好分步计算,先得到均值和标准差列,再基于这些列计算CV:
library(stringr) df2 <- df %>% group_by(group) %>% summarise( across(where(is.numeric), mean, na.rm = TRUE, .names = "{col}_mean"), across(where(is.numeric), sd, na.rm = TRUE, .names = "{col}_sd") ) %>% mutate( across(ends_with("_sd"), ~100 * (. / get(str_replace(cur_column(), "_sd", "_mean"))), .names = "{str_remove(col, '_sd')}_cv") )
通过cur_column()获取当前列名,替换后缀匹配对应的均值列,完成CV计算。
方案3:自定义CV函数(处理边界情况)
先编写一个带异常处理的CV函数,再在across中调用,可避免均值为0时的除以0报错:
# 自定义CV函数,均值为0时返回NA calc_cv <- function(x, na.rm = TRUE) { m <- mean(x, na.rm = na.rm) if (m == 0) return(NA_real_) 100 * (sd(x, na.rm = na.rm) / m) } # 调用自定义函数 df2 <- df %>% group_by(group) %>% summarise( across(where(is.numeric), mean, na.rm = TRUE, .names = "{col}_mean"), across(where(is.numeric), sd, na.rm = TRUE, .names = "{col}_sd"), across(where(is.numeric), calc_cv, na.rm = TRUE, .names = "{col}_cv") )
内容的提问来源于stack exchange,提问作者Bleras
相关产品推荐
相关产品推荐

