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

关于dnorm与geom_density绘图差异的技术问询

为什么这两段R代码生成的绘图不一样?

这是个很容易踩的ggplot2使用坑!核心原因是两段代码的绘图逻辑完全不是一回事——一个是直接绘制理论正态密度曲线,另一个是对输入的样本做核密度估计,而且样本本身的性质也和你预期的不符。让我详细拆解:

两段代码的核心逻辑差异

先明确每段代码在做什么:

代码1:绘制理论标准正态密度曲线

x <- seq(-4, 4, length.out = 100) 
data.frame(x, f = dnorm(x)) %>% ggplot(aes(x, f)) + geom_line()

这段代码的逻辑是:

  • 先生成均匀间隔的x值
  • 手动计算每个x对应的标准正态分布理论密度值(dnorm(x)就是标准正态在x点的密度)
  • 用geom_line()直接把(x, f)这组坐标点连接成线,本质是精准绘制理论上的钟形曲线。

代码2:对均匀样本做核密度估计

x <- seq(-4, 4, length.out = 100) 
data.frame(x, f = dnorm(x)) %>% ggplot() + geom_density(aes(x))

这段代码的逻辑和代码1完全无关:

  • 你虽然创建了包含f列的数据框,但geom_density(aes(x))完全忽略了f列的存在
  • 它把x列的100个均匀间隔值当作观测样本,用核密度估计(KDE)的方法去拟合这些样本的密度分布。

关键问题:你的“样本”是均匀分布的

seq(-4, 4, length.out = 100)生成的是均匀分布在-4到4之间的数值,而不是从标准正态分布中随机抽取的样本。用这些均匀分布的点做核密度估计,得到的结果会趋近于均匀分布的密度曲线(接近平坦,或因带宽参数有轻微波动),和标准正态的钟形曲线自然完全不同。

额外:geom_density的默认行为

就算你用标准正态的随机样本替代均匀x值,geom_density()的默认带宽参数(bw)是通过经验公式计算的,和理论正态密度的形状也会有细微差异;而且它会自动将估计的密度曲线归一化到积分等于1,但这不是导致两段图差异的核心原因。

如何让代码2得到和代码1一样的结果?

如果你想通过geom_density()重现代码1的理论曲线,可以利用weight参数让它参考你计算好的f值:

x <- seq(-4, 4, length.out = 100) 
data.frame(x, f = dnorm(x)) %>% ggplot() + geom_density(aes(x, weight = f))

不过其实完全没必要这么做——直接用代码1的geom_line()绘制理论值才是更直接准确的方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:05:15