关于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
相关产品推荐
相关产品推荐

