You need to enable JavaScript to run this app. R语言绘制对数正态密度曲线高度不符计算值且随x轴范围变化的问题
优惠活动
大模型
产品
解决方案
定价
更多

R语言绘制对数正态密度曲线高度不符计算值且随x轴范围变化的问题

对数正态分布PDF绘图时峰值与手动计算值不符问题

问题描述

  • 已确认分布参数:对数正态分布的对数均值为-0.4,对数标准差为2.5
  • 手动验算结果:通过对数正态概率密度函数(PDF)、R内置的dlnorm函数计算,当x = 0.001时,密度计算结果为5.389517:
    dlnorm(0.001, -0.4, 2.5)
    # 输出:5.389517
    
  • 第一种绘图情况:使用R基础绘图的curve函数,设置输入范围0到6时,呈现的密度曲线峰值仅略高于1.5,对应代码如下:
    curve(dlnorm(x, -.4, 2.5), xlim = c(0, 6), ylim = c(0, 6))
    
  • 第二种绘图情况:将输入范围调整为0到1时,绘制出的曲线峰值接近4,对应代码如下:
    curve(dlnorm(x, -.4, 2.5), xlim = c(0, 1), ylim = c(0, 6))
    
  • 复现验证:使用ggplot2绘制时存在完全相同的问题,对应代码如下:
    library(ggplot2)
    
    # x范围0-6的绘图
    ggplot(data = data.frame(x = 0), mapping = aes(x = x)) + 
      stat_function(fun = function(x) dlnorm(x, -0.4, 2.5)) + 
      xlim(0, 6) + 
      ylim(0, 6)
    
    # x范围0-1的绘图
    ggplot(data = data.frame(x = 0), mapping = aes(x = x)) + 
      stat_function(fun = function(x) dlnorm(x, -0.4, 2.5)) + 
      xlim(0, 1) + 
      ylim(0, 6)
    
  • 已验证绘制普通正态密度曲线时不会出现这类问题
  • 核心疑问:为何调整x轴刻度范围时,对数正态密度的绘制高度会发生变化?且上述两种绘制方式都无法呈现dlnorm计算得到的正确峰值高度?

原因与解决方案

核心原因1:该分布的理论峰值位置极度靠近x轴原点

对数正态分布PDF的极值点(峰值位置)可通过求导推导得到,公式为:

x_peak = exp(μ_log - σ_log²)

其中μ_log为对数均值,σ_log为对数标准差。代入本次的参数μ_log=-0.4,σ_log=2.5,计算得:
x_peak = exp(-0.4 - 2.5²) = exp(-6.65) ≈ 0.0013
也就是说,整个分布的全局峰值落在x≈0.0013的位置,和手动验算的x=0.001处的密度值位置完全重合。

核心原因2:默认绘图函数的采样步长过大,直接跳过了峰值所在的近0区域

R基础绘图的curve函数、ggplot2的stat_function默认仅生成101个等距分布的x采样点计算y值并连线:

  1. 当x范围设为0到6时,采样步长为 6/(101-1) = 0.06,所有采样点的序列为0, 0.06, 0.12, ..., 6,完全跳过了x在0到0.06之间的区域——这正是全局峰值所在的区间。此时看到的“仅略高于1.5”的峰值,是x>0.06区域内的局部密度最大值,和真正的全局峰值无关。
  2. 当x范围设为0到1时,采样步长为1/(101-1)=0.01,采样点序列为0, 0.01, 0.02, ..., 1,依然跳过了x在0到0.01之间的区域(峰值就在x≈0.0013,刚好落在这个被跳过的区间里)。此时看到的“接近4”的峰值,是x=0.01位置对应的密度值(计算可得dlnorm(0.01, -0.4, 2.5)≈3.88),依然不是全局最大值。

注:普通正态分布不存在该问题,是因为正态分布的峰值位置通常和x范围的中心重合,等距采样必然会覆盖到峰值附近的点,不会出现整段区间被跳过的情况。

修正方法

要完整绘制出包含正确峰值的曲线,只需要大幅提升采样密度,缩小采样步长即可:

  1. 基础绘图修改示例:将curve的采样点数从默认101提升到10000,步长会缩小到原来的1%,足以覆盖到x=0.001附近的峰值:
    curve(dlnorm(x, -.4, 2.5), xlim = c(0, 6), ylim = c(0, 6), n = 10000)
    
  2. ggplot2修改示例:为stat_function设置更大的采样点数:
    ggplot(data = data.frame(x = 0), mapping = aes(x = x)) + 
      stat_function(fun = function(x) dlnorm(x, -0.4, 2.5), n = 10000) + 
      xlim(0, 6) + 
      ylim(0, 6)
    

修改后绘制的曲线会完整呈现出x≈0.0013位置、高度约5.39的峰值,和dlnorm的手动计算值完全一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 23:27:01