如何在R中对无法手动求逆的CDF进行抽样?
在R中实现该CDF的抽样方法
因为无法手动推导该CDF的逆函数,我们可以用数值逆变换抽样的方法来生成样本,核心逻辑是:
- 生成服从均匀分布U(0,1)的随机数;
- 对每个均匀随机数,通过数值方法求解方程
flc_F(x) = u,得到对应的x值,即为目标分布的样本。
具体实现代码
1. 定义原CDF函数
a <- 3.1 be <- -0.15 ga <- 0.78 delt <- 0.12 c <- 3.5 b <- exp(a + be * c * (1 + c)) g <- exp((ga + delt * c) * c) flc_F <- function(x) { # x取值范围为0到1 if (x < 1) { return((b * (g - 1) * (1 - b^x)) / (b * (g - 1) + (1 - b * g) * b^x)) } else { return(1) } }
2. 实现数值逆CDF函数
利用R内置的uniroot函数求解方程,由于该CDF在x∈[0,1]上严格单调递增(从0到1),每个u∈(0,1)对应唯一的x:
flc_F_inv <- function(u) { # 处理边界情况 if (u == 0) return(0) if (u == 1) return(1) # 解方程 flc_F(x) - u = 0 root <- uniroot(function(x) flc_F(x) - u, interval = c(0, 1)) return(root$root) }
3. 生成样本
生成指定数量的样本,只需生成均匀随机数后逐个传入逆函数:
# 生成1000个样本 n <- 1000 u_samples <- runif(n) x_samples <- sapply(u_samples, flc_F_inv)
4. 验证抽样结果
可以绘制样本直方图,并叠加原分布的PDF(CDF求导得到)来验证:
# 定义PDF函数(CDF的导数) flc_f <- function(x) { if (x < 1) { numerator <- b*(g-1)*log(b)*b^x * (b*(g-1) + (1 - b*g)*b^x) + b*(g-1)*(1 - b^x)*(1 - b*g)*log(b)*b^x denominator <- (b*(g-1) + (1 - b*g)*b^x)^2 return(numerator / denominator) } else { return(0) } } # 绘图验证 hist(x_samples, prob = TRUE, breaks = 30, main = "抽样样本直方图与PDF", xlab = "x") curve(flc_f(x), from = 0, to = 1, add = TRUE, col = "red", lwd = 2)
注意事项
uniroot要求目标函数在区间端点符号相反,这里flc_F(0)=0 < u、flc_F(1)=1 > u,完全满足求解条件,结果稳定;- 边界值u=0和u=1直接返回x=0和x=1,无需调用数值求解。
内容的提问来源于stack exchange,提问作者user33484
相关产品推荐
相关产品推荐

