R语言计算数据框统计量时列名不符合预期问题排查
问题:计算数据框数值列均值和标准差时列名自动添加前缀
我用R代码计算class数据框数值列的均值和标准差,预期新列名为Age_mean、Age_std,但实际输出列名变成了Age.Age_mean、Age.Age_std,不清楚为什么会额外添加Age.前缀。
数据与代码
class <- structure(list(Name = c("Alfred", "Alice", "Barbara", "Carol", "Henry", "James", "Jane", "Janet", "Jeffrey", "John", "Joyce", "Judy", "Louise", "Mary", "Philip", "Robert", "Ronald", "Thomas", "William"), Sex = c("M", "F", "F", "F", "M", "M", "F", "F", "M", "M", "F", "F", "F", "F", "M", "M", "M", "M", "M"), Age = c(14, 13, 13, 14, 14, 12, 12, 15, 13, 12, 11, 14, 12, 15, 16, 12, 15, 11, 15), Height = c(69, 56.5, 65.3, 62.8, 63.5, 57.3, 59.8, 62.5, 62.5, 59, 51.3, 64.3, 56.3, 66.5, 72, 64.8, 67, 57.5, 66.5), Weight = c(112.5, 84, 98, 102.5, 102.5, 83, 84.5, 112.5, 84, 99.5, 50.5, 90, 77, 112, 150, 128, 133, 85, 112)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -19L)) out1 <- list() calc_mean <- function(data, vars, out) { vars <- syms(vars) print(vars) for (v in vars){ print(v) out1[[v]] <- data %>% summarise('{{v}}_mean' := mean(!! v), '{{v}}_std' := sd(!! v)) out2 <- data.frame(out1) assign(out, out2, envir =.GlobalEnv) } return(out2) } calc_mean(data=class, vars=c('Age','Height'), out='want')
实际输出
Age.Age_mean Age.Age_std Height.Height_mean Height.Height_std 1 13.31579 1.492672 62.33684 5.127075
原因分析
问题出在列表转数据框的命名规则:你将每个变量的统计结果存入列表out1时,用符号对象v(即Age、Height)作为列表元素名;当执行data.frame(out1)将列表转换为数据框时,R会自动用「列表元素名 + 点 + 原列名」的格式重命名列,以此区分不同列表元素中的列,最终就出现了Age.Age_mean这类带前缀的列名。
解决方案
方案1:修正原有循环逻辑
放弃用列表存储后转数据框的方式,改为逐个合并临时数据框,避免自动命名:
calc_mean <- function(data, vars, out) { vars <- syms(vars) # 初始化空的 tibble out2 <- tibble() for (v in vars){ # 生成当前变量的统计结果 temp <- data %>% summarise('{{v}}_mean' := mean(!!v), '{{v}}_std' := sd(!!v)) # 合并到结果数据框 out2 <- bind_cols(out2, temp) } assign(out, out2, envir = .GlobalEnv) return(out2) }
方案2:用across简化代码(推荐)
使用tidyverse的across函数,无需循环即可批量处理所有目标变量,直接生成符合预期的列名:
calc_mean <- function(data, vars, out) { out2 <- data %>% summarise( across( all_of(vars), list(mean = mean, std = sd), .names = "{.col}_{.fn}" # 自定义列名格式:变量名_统计量 ) ) assign(out, out2, envir = .GlobalEnv) return(out2) }
运行修正后的函数,want数据框的列名将变为Age_mean、Age_std、Height_mean、Height_std,完全符合预期。
内容的提问来源于stack exchange,提问作者jkatam
相关产品推荐
相关产品推荐

