如何批量对多列数据执行Mann-Whitney U检验(wilcox.test)
批量执行Mann-Whitney U检验的解决方案
问题背景
现有数据集包含分组列Group(分为A、B两组)及43列元素数值数据,部分数据含NA值。手动拆分数据集为A、B子集后对单列执行Mann-Whitney U检验(wilcox.test)效率极低,直接传入数据框或多列时出现'x' must be numeric错误,需要批量执行检验的方法。
数据集示例:
| Area | Al | Cd | Cu |
|---|---|---|---|
| A | 10000 | 0.2 | 30 |
| A | 15000 | 0.5 | 25 |
| A | NA | Na | NA |
| B | 8000 | 1.1 | 55 |
| B | 11000 | 0.2 | 40 |
| B | 13000 | 0.1 | 40 |
部分数据的dput结构:
structure(list(Group = c("A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B" ), Al = c(NA, NA, NA, 18100, 18400, 32500, 33200, 31200, 17400, 13900, 14400), As = c(NA, NA, NA, 16.9, 14.6, 8.83, 8.59, 8.42, 13.4, 13.5, 13.7), B = c(NA, NA, NA, 18, 16, 14, 14, 11, 53, 87, 58), Bi = c(NA, NA, NA, 0.13, 0.12, 0.57, 0.55, 0.52, 0.22, 0.18, 0.21), Ca = c(NA, NA, NA, 5950, 5480, 6220, 6230, 5950, 6850, 8170, 7000), Cd = c(NA, NA, NA, 0.2, 0.2, 0.2, 0.2, 0.18, 0.31, 0.36, 0.46)), row.names = c(1L, 2L, 3L, 4L, 5L, 40L, 41L, 42L, 43L, 44L, 45L), class = c("tbl_df", "tbl", "data.frame"))
手动单列检验代码:
# Data是上述数据框 Area_A <- subset(Data, Group %in% c("A")) Area_B <- subset(Data, Group %in% c("B")) WhitneyU_Al <- wilcox.test(Area_A$Al, Area_B$Al, na.rm = TRUE, paired = FALSE, exact = FALSE)
尝试的批量代码(报错):
WhitneyU <- wilcox.test(Area_A, Area_B, na.rm = TRUE, paired = FALSE, exact = FALSE) # OR WhitneyU <- wilcox.test(Area_A[2:43], Area_B[2:43], na.rm = TRUE, paired = FALSE, exact = FALSE)
解决方案
第一步:数据预处理(解决'x' must be numeric错误)
首先检查并转换所有待检验列的数值类型,将字符串型的"Na"替换为标准NA,并确保列是numeric类型:
# 用tidyverse实现 library(tidyverse) Data_cleaned <- Data %>% mutate(across(-Group, ~ ifelse(.x == "Na", NA, .x) %>% as.numeric())) # 用base R实现 Data_cleaned <- Data for(col in setdiff(names(Data_cleaned), "Group")){ Data_cleaned[[col]] <- as.numeric(ifelse(Data_cleaned[[col]] == "Na", NA, Data_cleaned[[col]])) }
第二步:批量执行检验
方法1:Base R 实现(无需额外包)
使用lapply遍历所有数值列,对每列执行wilcox.test:
# 获取所有待检验的列名(排除Group列) test_cols <- setdiff(names(Data_cleaned), "Group") # 批量执行检验 wilcox_results <- lapply(test_cols, function(col){ x <- Data_cleaned[Data_cleaned$Group == "A", col] y <- Data_cleaned[Data_cleaned$Group == "B", col] wilcox.test(x, y, na.rm = TRUE, paired = FALSE, exact = FALSE) }) # 给结果命名,方便查看 names(wilcox_results) <- test_cols # 查看指定列结果,比如Al wilcox_results$Al
方法2:Tidyverse 实现(结果结构化)
使用purrr::map结合dplyr,将检验结果整理成数据框格式,便于后续分析:
library(purrr) library(dplyr) # 批量执行并整理结果为数据框 wilcox_df <- Data_cleaned %>% select(-Group) %>% map_dfr(function(col){ x <- col[Data_cleaned$Group == "A"] y <- col[Data_cleaned$Group == "B"] res <- wilcox.test(x, y, na.rm = TRUE, paired = FALSE, exact = FALSE) tibble( statistic = res$statistic, p_value = res$p.value, method = res$method ) }, .id = "element") # 查看结构化结果 print(wilcox_df)
结果说明
- Base R方法返回列表格式的检验结果,可通过列名直接调取单条结果;
- Tidyverse方法返回结构化数据框,更适合批量查看、筛选或可视化统计结果。
内容的提问来源于stack exchange,提问作者SleeplessPHD
相关产品推荐
相关产品推荐

