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

在ggplot2的geom_histogram中添加dnorm曲线遇问题求助

解决ggplot绘制标准化变量直方图+dnorm曲线的问题

问题1:首次运行曲线过宽

这是因为直方图默认以计数(count)为y轴,而dnorm输出的是密度值,两者尺度差异极大,导致曲线被过度拉伸。解决方法很直接:

  • 将直方图的y轴切换为密度,在geom_histogram()中设置aes(y = ..density..),让其与dnorm的输出尺度匹配,曲线就会恢复正常比例。
  • 示例代码:
library(ggplot2)
# 先清理缺失值
df_clean <- df[is.finite(df$oes_scale), ]

ggplot(data = df_clean, aes(x = oes_scale)) +
  geom_histogram(aes(y = ..density..), bins = 30, fill = "lightblue", color = "black") +
  stat_function(
    fun = dnorm,
    args = list(mean = mean(df_clean$oes_scale), sd = sd(df_clean$oes_scale)),
    color = "red", size = 1
  )

问题2:相对频率模式下添加stat_function报错

报错原因

你遇到的「density * 0.35」非数值运算问题,核心是直方图用了相对频率(比如y = ..count../sum(..count..)),而stat_function默认输出密度值,两者的y轴尺度不兼容;警告里的6行非有限值,是数据中存在NA/NaN/Inf,会干扰后续运算。

解决步骤

  1. 先清理数据:提前移除含非有限值的行,从根源避免运算异常:
df_clean <- df[is.finite(df$oes_scale), ]
  1. 对齐相对频率与dnorm的尺度:相对频率总和为1,密度曲线下面积也为1,但直方图组距会影响相对频率的数值。需要把dnorm的结果乘以组距,让曲线和相对频率的y轴匹配:
    • 先确定组距,要么手动指定,要么从直方图中提取:
    # 方式1:手动指定组距
    bin_width <- diff(range(df_clean$oes_scale)) / 30
    # 方式2:从已绘制的直方图中提取实际组距
    p_temp <- ggplot(df_clean, aes(x=oes_scale)) + geom_histogram(bins=30)
    bin_width <- ggplot_build(p_temp)$data[[1]]$width[1]
    
    • 再绘制带匹配曲线的直方图:
ggplot(data = df_clean, aes(x = oes_scale)) +
  geom_histogram(aes(y = ..count../sum(..count..)), binwidth = bin_width, fill = "lightblue", color = "black") +
  stat_function(
    fun = function(x) dnorm(x, mean = mean(df_clean$oes_scale), sd = sd(df_clean$oes_scale)) * bin_width,
    color = "red", size = 1
  )
  1. 简化替代方案:如果不需要严格展示相对频率数值,直接用密度模式(y=..density..)更省心——密度和相对频率的趋势完全一致,只是数值差一个组距倍数,不影响图形的对比展示,还能避免尺度匹配的麻烦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 11:55:12