R中概率密度函数曲线超出边界时无法正确绘制的问题及修正需求
问题原因与解决方案
为什么曲线在边界处没有直接归零?
- 离散采样的衔接问题:
curve或geom_function都是通过绘制离散采样点的连线生成曲线。默认采样点数量有限(比如geom_function默认n=101),在0-40范围内的采样点间隔为0.4。这导致x=9.6处(norm_pdf=0)和x=10处(norm_pdf非零)之间会画出一条斜线,而非理论上的垂直边界,视觉上就像曲线没有直接归零。 - 函数本身的边界取值:
dunif(x,10,30)在x=10和x=30处返回1/20=0.05(符合连续均匀分布的密度定义),所以norm_pdf(10)和norm_pdf(30)本身是非零值,而边界外的点取值为0,采样点的连线放大了这种过渡效果。
如何实现符合定义的正确绘图?
方法1:手动构造带关键节点的绘图数据
直接生成包含边界点、边界外区间和区间内密集采样点的数据框,确保曲线在边界处垂直衔接:
library(ggplot2) # 保留原函数定义 f <- function(z) 2*z^2 - 15*z + 15 fp <- function(x) f(x) * dunif(x, 10, 30) norm_const <- function(func, l=10, u=30) integrate(func, l, u)$value norm_pdf <- function(x) ifelse(x < 10 | x > 30, 0, fp(x) / norm_const(fp)) # 构造包含边界的采样点:左边界外、10、区间内、30、右边界外 x_vals <- c(seq(0, 9.99, length.out=20), 10, seq(10.01, 29.99, length.out=100), 30, seq(30.01, 40, length.out=20)) plot_data <- data.frame(x = x_vals, y = norm_pdf(x_vals)) # 绘图 ggplot(plot_data, aes(x, y)) + geom_line() + xlab("x") + ylab("Density") + theme_minimal() + scale_x_continuous(limits=c(0, 40), breaks=seq(0, 40, 2))
这种方式让曲线在x<10时保持0,x=10处直接跳转到对应密度值,彻底消除过渡斜线。
方法2:增强采样密度并强制包含边界
如果想用geom_function,可以提高采样点数量并确保边界点被包含,让过渡斜线几乎不可见:
library(ggplot2) # 显式定义函数的边界行为 norm_pdf <- function(x) ifelse(x < 10 | x > 30, 0, fp(x) / norm_const(fp)) # 用501个采样点(间隔0.08),确保边界点在采样范围内 ggplot() + geom_function(fun = norm_pdf, n = 501, xlim = c(0, 40)) + xlab("x") + ylab("Density") + theme_minimal() + scale_x_continuous(limits=c(0, 40), breaks=seq(0, 40, 2)) + # 可选:添加虚线标注边界 geom_vline(xintercept = c(10, 30), color = "red", linetype = "dashed")
更多的采样点会让边界处的过渡斜线变得极窄,视觉上接近垂直边界。
方法3:分段绘制(完全贴合理论定义)
直接绘制三段曲线:边界外的水平线、区间内的函数曲线、边界处的垂直线,完全符合概率密度函数的定义:
library(ggplot2) # 计算边界处的密度值 pdf_at_10 <- norm_pdf(10) pdf_at_30 <- norm_pdf(30) ggplot() + # 左边界外:0到10,y=0 geom_segment(aes(x=0, y=0, xend=10, yend=0)) + # 右边界外:30到40,y=0 geom_segment(aes(x=30, y=0, xend=40, yend=0)) + # 区间内的密度曲线 geom_function(fun = norm_pdf, xlim = c(10, 30)) + # 边界处的垂直线 geom_segment(aes(x=10, y=0, xend=10, yend=pdf_at_10), color="red") + geom_segment(aes(x=30, y=0, xend=30, yend=pdf_at_30), color="red") + xlab("x") + ylab("Density") + theme_minimal() + scale_x_continuous(limits=c(0, 40), breaks=seq(0, 40, 2))
这种方式完美呈现了“边界外为0、边界处垂直衔接、边界内为函数曲线”的理论效果。
内容的提问来源于stack exchange,提问作者arezaie
相关产品推荐
相关产品推荐

