You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在R语言中绘制多人口统计学分组箱线图并添加对应p值?

在R中绘制整合多箱线图并添加分组差异p值

以下是实现需求的完整步骤,包含数据处理、统计检验和绘图代码:

1. 加载必要的包

library(tidyverse)  # 数据处理+绘图
library(rstatix)    # 便捷统计检验

2. 准备/导入数据

先模拟一份示例数据集(替换成你的真实数据即可):

set.seed(123)  # 保证结果可重复
df <- tibble(
  ID = 1:200,
  V1 = c(rnorm(100, 50, 10), rnorm(50, 55, 10), rnorm(50, 45, 10)),
  性别 = sample(c("男", "女"), 200, replace = TRUE),
  年龄组 = sample(c("18-30", "31-50", "51+"), 200, replace = TRUE),
  教育程度 = sample(c("高中及以下", "本科", "硕士及以上"), 200, replace = TRUE)
)

3. 数据格式转换

将宽格式数据转为长格式,统一处理所有人口统计学分组变量:

df_long <- df %>%
  select(-ID) %>%
  pivot_longer(cols = -V1, names_to = "分组变量", values_to = "分组水平")

4. 计算分组差异p值

根据分组水平数量选择检验方法:二分类用Wilcoxon秩和检验,多分类用Kruskal-Wallis检验(若数据符合正态分布+方差齐性,可替换为t.test或anova):

p_values <- df_long %>%
  group_by(`分组变量`) %>%
  summarise(
    p = get_pvalue(V1 ~ `分组水平`, 
                   method = ifelse(n_distinct(`分组水平`) == 2, "wilcox.test", "kruskal.test"))$p,
    .groups = "drop"
  ) %>%
  mutate(
    # 格式化p值标签,提升可读性
    p_label = case_when(
      p < 0.001 ~ "p < 0.001",
      p < 0.01 ~ paste0("p = ", round(p, 3)),
      TRUE ~ paste0("p = ", round(p, 2))
    ),
    # 设置p值标注的Y轴位置(略高于V1的最大值)
    y_pos = max(df$V1) * 1.1
  )

5. 绘制整合箱线图(分面版,更清晰)

将不同人口统计学变量拆分为子图,每个子图上方标注对应的p值:

ggplot(df_long, aes(x = `分组水平`, y = V1)) +
  geom_boxplot(fill = "#4292c6", alpha = 0.7) +
  # 按分组变量分面,X轴自适应每个变量的水平
  facet_wrap(~`分组变量`, scales = "free_x") +
  # 添加p值标注
  geom_text(data = p_values, aes(x = 1, y = y_pos, label = p_label), 
            hjust = 0.5, size = 4, fontface = "bold") +
  # 美化主题
  theme_bw() +
  labs(x = "分组", y = "V1", title = "V1在不同人口统计学分组下的分布及差异p值") +
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
    axis.title = element_text(size = 12),
    strip.text = element_text(size = 12, face = "bold")
  )

可选:同一X轴版(不分面)

若希望所有分组放在同一X轴展示:

# 生成合并的X轴标签
df_long <- df_long %>%
  mutate(x_label = paste(`分组变量`, `分组水平`, sep = "\n"))

# 计算p值标注的X轴位置(每个分组变量的中间位置)
p_values <- df_long %>%
  group_by(`分组变量`) %>%
  summarise(
    p = get_pvalue(V1 ~ `分组水平`, 
                   method = ifelse(n_distinct(`分组水平`) == 2, "wilcox.test", "kruskal.test"))$p,
    x_pos = median(which(df_long$`分组变量` == cur_group()$`分组变量`)),
    .groups = "drop"
  ) %>%
  mutate(
    p_label = case_when(
      p < 0.001 ~ "p < 0.001",
      p < 0.01 ~ paste0("p = ", round(p, 3)),
      TRUE ~ paste0("p = ", round(p, 2))
    ),
    y_pos = max(df$V1) * 1.1
  )

# 绘图
ggplot(df_long, aes(x = x_label, y = V1)) +
  geom_boxplot(fill = "#4292c6", alpha = 0.7) +
  geom_text(data = p_values, aes(x = x_pos, y = y_pos, label = p_label), 
            size = 4, fontface = "bold") +
  theme_bw() +
  labs(x = "人口统计学分组", y = "V1", title = "V1在不同人口统计学分组下的分布及差异p值") +
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
    axis.title = element_text(size = 12),
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

注意事项

  • 若你的真实数据中分组变量是字符型,建议用factor()转换为因子类型,可自定义水平顺序。
  • 若数据符合正态分布且方差齐性,可将检验方法替换为t.test(二分类)或anova(多分类)。
  • 可根据需求调整箱线图颜色、主题样式、p值标注位置等参数。

内容的提问来源于stack exchange,提问作者Gerda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 17:12:22