如何使用饼图对比聚类与总体的分类变量分布?
实现聚类与总体分类变量相对频率的嵌套饼图(甜甜圈图)
我刚好做过类似的可视化需求,用嵌套饼图(也就是甜甜圈图)来对比聚类分组和总体人群的分类变量相对频率,确实能直观展现两者的分布差异。下面我就用你提供的示例数据,一步步实现这个效果。
方法一:提前整理频率数据(更清晰可控)
首先我们先把总体和聚类1的相对频率计算好,整理成适合绘图的格式,这样后续绘图逻辑更清晰:
# 加载需要的包 library(ggplot2) library(dplyr) # 你的示例数据集 mydf <- data.frame(week_day = as.factor(c(rep("monday",10), rep("monday",5), rep("tuesday",5))), cluster = c(rep(1,10), rep(2,10))) # 计算总体人群的相对频率 overall_data <- mydf %>% count(week_day) %>% mutate(rel_freq = n / sum(n), group = "总体") # 计算聚类1的相对频率 cluster1_data <- mydf %>% filter(cluster == 1) %>% count(week_day) %>% mutate(rel_freq = n / sum(n), group = "聚类1") # 合并数据,并为不同分组设置半径(区分内外层) plot_data <- bind_rows(overall_data, cluster1_data) %>% mutate(radius = ifelse(group == "总体", 0.5, 1))
接下来用ggplot绘制嵌套饼图:
ggplot(plot_data, aes(x = radius, y = rel_freq, fill = week_day)) + # 绘制环形条形图,width控制环的宽度 geom_bar(stat = "identity", width = 0.5, color = "white") + # 转换为极坐标,得到饼图效果 coord_polar("y", start = 0) + # 设置配色方案 scale_fill_brewer(palette = "Set2") + # 添加标题和图例名称 labs(title = "聚类1与总体人群week_day相对频率对比", fill = "星期") + # 调整主题,去掉冗余元素 theme_minimal() + theme(axis.text = element_blank(), axis.title = element_blank(), panel.grid = element_blank(), legend.position = "bottom") + # 添加百分比标签,让数值更直观 geom_text(aes(label = paste0(round(rel_freq*100, 1), "%")), position = position_stack(vjust = 0.5))
方法二:直接在ggplot中计算相对频率(更简洁)
如果你不想提前整理数据,也可以直接在geom_bar里用(..count..)/sum(..count..)实时计算相对频率,分图层绘制内外饼图:
ggplot() + # 绘制内层:总体人群的相对频率分布 geom_bar(data = mydf, aes(x = 0.5, y = (..count..)/sum(..count..), fill = week_day), stat = "count", width = 0.5, color = "white") + # 绘制外层:聚类1的相对频率分布 geom_bar(data = filter(mydf, cluster == 1), aes(x = 1, y = (..count..)/sum(..count..), fill = week_day), stat = "count", width = 0.5, color = "white") + # 转换为极坐标 coord_polar("y", start = 0) + scale_fill_brewer(palette = "Set2") + labs(title = "聚类1与总体人群week_day相对频率对比", fill = "星期") + theme_minimal() + theme(axis.text = element_blank(), axis.title = element_blank(), panel.grid = element_blank(), legend.position = "bottom") + # 手动添加百分比标签(需要用到之前计算好的频率数据) geom_text(data = overall_data, aes(x = 0.5, y = rel_freq, label = paste0(round(rel_freq*100,1), "%")), position = position_stack(vjust = 0.5)) + geom_text(data = cluster1_data, aes(x = 1, y = rel_freq, label = paste0(round(rel_freq*100,1), "%")), position = position_stack(vjust = 0.5))
关键细节说明
- 我们通过设置不同的
x值(radius)来区分内层(总体)和外层(聚类1),width参数控制环形的宽度,让内外层有明显区分。 - 用
coord_polar("y")把条形图转换成极坐标,就得到了嵌套饼图的效果。 - 添加百分比标签可以让每个分类的相对频率一目了然,
position_stack(vjust = 0.5)保证标签在每个扇形的中心位置。
内容的提问来源于stack exchange,提问作者Seymour
相关产品推荐
相关产品推荐

