如何用dplyr按条件批量汇总多变量:正态/非正态分布统计量计算
批量按正态分布类型汇总数据(mtcars示例)
方法一:使用dplyr的across批量处理
这种方式贴合tidyverse风格,代码简洁高效:
library(dplyr) # 手动指定正态变量(可根据实际检验结果调整) norm_vars <- c("qsec", "drat", "hp", "mpg") # 自动生成非正态变量(排除分组变量am) non_norm_vars <- setdiff(names(mtcars), c("am", norm_vars)) # 分组批量汇总 summary_df <- mtcars %>% group_by(am) %>% summarise( # 正态变量:输出 mean (sd),保留两位小数 across(all_of(norm_vars), ~paste0(round(mean(.x, na.rm = TRUE), 2), " (", round(sd(.x, na.rm = TRUE), 2), ")"), .names = "{.col}_mean_sd"), # 非正态变量:输出 median (Q1-Q3),保留两位小数 across(all_of(non_norm_vars), ~{ qs <- quantile(.x, na.rm = TRUE) paste0(round(median(.x, na.rm = TRUE), 2), " (", round(qs[2], 2), "-", round(qs[4], 2), ")") }, .names = "{.col}_median_iqr") ) # 查看结果 print(summary_df)
自动判断正态性(可选)
如果不想手动指定变量,可通过 Shapiro-Wilk 检验自动筛选(注意:该检验适合小样本,大样本易因微小偏差拒绝原假设):
library(purrr) # 批量执行正态性检验 norm_test_results <- mtcars %>% select(-am) %>% map_df(~tibble(p_value = shapiro.test(.x)$p.value), .id = "variable") # 以p>0.05为标准划分变量 auto_norm_vars <- norm_test_results %>% filter(p_value > 0.05) %>% pull(variable) auto_non_norm_vars <- norm_test_results %>% filter(p_value <= 0.05) %>% pull(variable) # 将上述汇总代码中的norm_vars/non_norm_vars替换为自动生成的变量即可
方法二:for循环结合rbind处理
若习惯循环逻辑,可采用以下方案:
# 初始化空结果数据框 summary_loop <- data.frame() # 遍历am的每个分组值 for (group_val in unique(mtcars$am)) { # 提取当前分组的数据 group_data <- mtcars[mtcars$am == group_val, ] # 计算正态变量的mean±sd norm_stats <- sapply(norm_vars, function(var) { val <- group_data[[var]] paste0(round(mean(val, na.rm = TRUE), 2), " (", round(sd(val, na.rm = TRUE), 2), ")") }) # 计算非正态变量的中位数及四分位数 non_norm_stats <- sapply(non_norm_vars, function(var) { val <- group_data[[var]] qs <- quantile(val, na.rm = TRUE) paste0(round(median(val, na.rm = TRUE), 2), " (", round(qs[2], 2), "-", round(qs[4], 2), ")") }) # 合并当前分组结果并绑定到总数据框 current_row <- data.frame(am = group_val, t(c(norm_stats, non_norm_stats))) summary_loop <- rbind(summary_loop, current_row) } # 设置清晰的列名 colnames(summary_loop) <- c("am", paste0(norm_vars, "_mean_sd"), paste0(non_norm_vars, "_median_iqr")) # 查看结果 print(summary_loop)
内容的提问来源于stack exchange,提问作者Mark Davies
相关产品推荐
相关产品推荐

