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

如何用ggplot2制作按类别着色且基于整体密度的密度直方图

解决方案:基于整体数据计算密度的分组着色直方图

要让直方图的密度基于整个数据集而非分组后的数据,你需要手动计算密度(替代默认按组计算的density统计量),确保分母使用全局总样本数而非组内样本数。结合stage()函数可以清晰实现这一点,它允许你在统计变换前后分别指定变量逻辑:

library(ggplot2)

# 数据预处理
d <- diamonds
priceBreaks <- c(0,5000,10000,20000)
d$priceCat <- cut(diamonds$price, breaks = priceBreaks, labels = c('low','med','high'))

# 生成目标直方图
ggplot(d) +
  geom_histogram(
    aes(
      x = price,
      # 使用stage:原始x用于分箱,统计后用全局总样本数计算密度
      y = stage(
        x = price,
        after_stat = count / (nrow(d) * binwidth)
      ),
      fill = priceCat
    ),
    breaks = seq(0,20000,by=1000),
    color = "white" # 可选:添加组间分隔线,提升可读性
  ) +
  labs(y = "Density")

原理说明

  • 默认的after_stat(density)会按fill分组计算:每个组的密度 = 组内bin计数 / (组内样本数 × 组距),导致各组密度之和大于1。
  • 手动计算时,用nrow(d)(整个数据集的总样本数)替代组内样本数,得到的是整体数据的密度:每个bin的密度 = bin计数 / (全局总样本数 × 组距),所有bin的密度之和为1。

stage()函数的作用

这里stage()的核心是分离"原始数据映射"和"统计后计算"两个阶段:

  • x = price:指定分箱时使用原始的price变量(基于整个数据集的范围分箱,不受分组影响);
  • after_stat = ...:在统计完成(生成count和binwidth等统计量)后,用全局总样本数计算密度,确保密度基于整体分布。

你也可以不用stage(),直接在after_stat()里写计算式,效果一致:

ggplot(d) +
  geom_histogram(
    aes(x = price, y = after_stat(count / (nrow(d) * binwidth)), fill = priceCat),
    breaks = seq(0,20000,by=1000)
  )

内容的提问来源于stack exchange,提问作者S. Robinson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 15:04:53