如何在ggh4x分面图中适配带最小值的指数理论分布?
解决ggh4x::stat_theodensity适配带偏移量指数分布与自定义拟合方法的问题
问题背景
开发Shiny应用时需要实现:对数据集进行泊松、正态、指数分布检验,返回统计结果并绘制数据密度与理论分布曲线,同时支持多数据集分面展示。但使用ggh4x::stat_theodensity绘制指数分布时遇到两个核心问题:
- 行业数据普遍存在非零最小值,而
stat_theodensity默认调用的dexp无法适配该偏移量,导致理论曲线与实际数据不匹配 - 尝试循环为每个分面设置对应数据的xmin时,仅第二个分面的理论曲线生效,首次循环还触发
fitdist()错误(错误码100)
核心需求
- 让
stat_theodensity自动识别每个分面数据的最小值,适配带偏移量的指数分布 - 通过
stat_theodensity传递fitdistrplus::fitdist()的自定义拟合方法(如method="mse")
解决方案与代码实现
关键思路
默认stat_theodensity针对标准指数分布(x≥0),而带偏移量的指数分布可表示为X = x0 + Y(Y为标准指数分布,x0为数据最小值)。我们需要自定义拟合与密度计算函数,让stat_theodensity支持这种偏移场景,同时利用fit.arg参数传递拟合方法。
library(ggh4x) library(fitdistrplus) # 生成带偏移量的指数分布测试数据 data1 <- rexp(n = 500, rate = 1/100) + 100 data2 <- rexp(n = 500, rate = 1/250) + 500 plot_dat <- data.frame( ID = rep(c("Set 1", "Set 2"), each = 500), data = c(data1, data2) ) # 自定义带偏移量的指数分布拟合函数 fit_exp_offset <- function(x, ...) { x0 <- min(x) # 获取当前分面数据的最小值(偏移量) y <- x - x0 # 将数据平移至标准指数分布的定义域 # 调用fitdist并传递自定义拟合方法 fit_result <- fitdist(y, distr = "exp", ...) # 将偏移量加入拟合结果,供后续密度计算使用 fit_result$estimate <- c(fit_result$estimate, x0 = x0) return(fit_result) } # 自定义带偏移量的指数分布密度计算函数 dexp_offset <- function(x, rate, x0) { # 仅在x >= 偏移量时计算密度,否则返回0 ifelse(x >= x0, dexp(x - x0, rate = rate), 0) } # 绘制分面密度图与理论分布曲线 ggplot(plot_dat, aes(x = data)) + geom_density(color = "red", linewidth = 0.8) + stat_theodensity( distri = "exp_offset", # 指定使用自定义的带偏移量指数分布 fit.arg = list(method = "mse"), # 传递fitdist的拟合方法参数 color = "blue", linewidth = 1 ) + facet_wrap(~ID, scales = "free") # 分面展示,自动适配每个分组的偏移量
代码说明
自定义拟合函数
fit_exp_offset:- 自动计算当前分面数据的最小值x0作为偏移量
- 将原始数据平移至标准指数分布的定义域(x≥0)
- 调用
fitdist()并接受自定义参数(如method="mse") - 将偏移量存入拟合结果,供密度计算使用
自定义密度函数
dexp_offset:- 根据拟合得到的速率参数与偏移量,计算原始数据的理论密度
- 对小于偏移量的x值返回0,符合指数分布的定义域要求
stat_theodensity参数配置:- 通过
distri指定自定义分布名称exp_offset - 通过
fit.arg传递method="mse"给fitdist(),实现自定义拟合逻辑 - 分面逻辑会自动对每个分组应用自定义函数,无需手动循环添加图层
- 通过
内容的提问来源于stack exchange,提问作者Steven Ouellette
相关产品推荐
相关产品推荐

