如何在一张图中可视化两组差异极大的分布数据?
解决极端偏态数据与正态分布数据的并列可视化问题
这个场景我太熟悉了——当一组数据有大量极端集中的数值(比如你的组a里95个值都是1),常规的箱线图和小提琴图确实会掉链子:箱线图直接挤在顶部,啥细节都看不到;小提琴图则会因为1处的密度太高,呈现出异常的形态。下面给你几个实用的可视化方案,结合你的示例数据来实现:
方案1:抖动散点+自定义统计标注(最直观)
既然组a的大部分值集中在1,我们可以保留抖动散点展示原始数据,同时给两组添加关键统计量(比如中位数、四分位距),再标注组a中等于1的样本数,这样既能看到原始数据,又能清晰对比两组差异。
library(tidyverse) # 预处理数据,计算各组统计量 d_summary <- d %>% group_by(var) %>% summarize( median_val = median(val), q1_val = quantile(val, 0.25), q3_val = quantile(val, 0.75), count_1 = sum(val == 1) ) d %>% ggplot(aes(x = var, y = val)) + geom_jitter(width = 0.2, alpha = 0.6, size = 1.5) + # 抖动散点展示原始数据分布 # 添加中位数线和四分位距竖线 geom_segment(data = d_summary, aes(x = as.numeric(var)-0.15, xend = as.numeric(var)+0.15, y = median_val, yend = median_val), color = "red", size = 1) + geom_segment(data = d_summary, aes(x = as.numeric(var), xend = as.numeric(var), y = q1_val, yend = q3_val), color = "red", size = 1) + # 标注组a中1的数量 geom_text(data = filter(d_summary, var == "a"), aes(x = var, y = 0.9, label = paste0("n=1: ", count_1)), color = "darkblue", size = 4) + labs(title = "抖动散点+统计标注对比", x = "组别", y = "响应值") + theme_minimal()
这个方案的优势是保留了原始数据的全貌,统计线快速展示集中趋势,极端值的数量也一目了然,不会让人误解分布。
方案2:分面密度曲线+散点补充
如果想更清晰地展示两组的分布形态,用分面的密度曲线是个好选择——既能看到组b的正态分布,又能在组a的分面里用散点补充极端值的数量信息。
d %>% ggplot(aes(x = val)) + geom_density(fill = "lightblue", alpha = 0.6) + # 给组a的散点单独放在底部,避免遮挡密度曲线 geom_jitter(data = filter(d, var == "a"), aes(y = 0.5), width = 0, height = 0.2, alpha = 0.5) + facet_wrap(~var, ncol = 1) + labs(title = "分面密度曲线对比", x = "响应值", y = "密度") + theme_minimal()
分面的方式避免了两组分布差异过大导致的视觉干扰,密度曲线清晰展示组b的形态,组a的散点则直观呈现了大量1的存在。
方案3:优化小提琴图,突出极端值
如果你还是想保留小提琴图的形式,可以通过调整参数解决宽度异常的问题,再配合散点和文本标注补充关键信息:
d %>% ggplot(aes(x = var, y = val)) + geom_violin(scale = "count", width = 0.8) + # scale="count"让宽度对应样本数,避免极端密度导致的异常宽度 geom_jitter(width = 0.1, alpha = 0.7, size = 1) + # 直接标注组a的极端值情况 geom_text(aes(x = "a", y = 0.8, label = "95个值为1"), color = "darkred", size = 4) + labs(title = "优化后的小提琴图+抖动散点", x = "组别", y = "响应值") + theme_minimal()
scale="count"参数让小提琴宽度对应每组样本数,而非密度,避免了组a在1处的极高密度导致的异常形态,散点和文本则补充了原始数据的细节。
方案4:横向点图展示分布
点图可以把每个样本点整齐排列,直观看到组a的点几乎都堆叠在1,组b的点呈正态分布的形态:
d %>% ggplot(aes(x = val, y = var)) + geom_dotplot(binaxis = "x", stackdir = "center", dotsize = 0.8) + labs(title = "横向点图对比分布", x = "响应值", y = "组别") + theme_minimal()
横向布局让两组的分布对比非常直观,不需要额外标注就能看出两组的核心差异。
内容的提问来源于stack exchange,提问作者petyar
相关产品推荐
相关产品推荐

