对称分布
虽然 OP 的例子不完全对称,但足够接近 - 并且有用的是从那里开始,因为解决方案更简单。
您可以使用 integrate
和 optimize
的组合。我将其编写为自定义函数,但请注意,如果您在其他情况下使用此函数,则可能需要重新考虑搜索分位数的边界。
f_quan <- function(fun, probs, range=c(0,1)){
mode <- optimize(fun, interval = range, maximum = TRUE, tol = 1e-12)[[1]]
total_area <- integrate(fun, range[1], range[2])[[1]]
O <- function(d){
parea <- integrate(fun, mode-d, mode+d)[[1]] / total_area
(probs - parea)^2
}
o <- optimize(O, c(0,range[2]/2 - 1E-02))[[1]]
return(c(mode-o, mode+o))
}
像这样使用它,
f <- f_quan(posterior, 0.95)
curve(posterior, n = 1e4)
abline(v=f, col="blue", lwd=2, lty=3)
提供
非对称分布
在非对称分布的情况下,我们需要搜索两个满足 P(a < x < b) = Prob 的点,其中 Prob 是某个期望概率。由于有无限多个区间 (a,b) 满足这一点,因此 OP 建议找到最短的一个。
解决方案中重要的是定义一个 domain
,即我们想要搜索的区域(我们不能使用 -Inf, Inf
,因此用户必须将其设置为合理的值)。
prob_ab <- function(fun, a, b, domain){
totarea <- integrate(fun, domain[1], domain[2])[[1]]
integrate(fun, a, b)[[1]] / totarea
}
invert_prob_ab <- function(fun, a, prob, domain){
O <- function(b, fun, a, prob){
(prob_ab(fun, a, b, domain=domain) - prob)^2
}
b <- optimize(O, c(a, domain[2]), a = a, fun=fun, prob=prob)$minimum
return(b)
}
prob_int_shortest <- function(fun, prob, domain){
mode <- optimize(fun, interval = domain, maximum = TRUE, tol = 1e-12)[[1]]
O <- function(a, fun, prob, domain){
b <- invert_prob_ab(fun, a, prob, domain)
b - a
}
abest <- optimize(O, c(0,mode), fun=fun, prob=prob, domain=domain)$minimum
b <- invert_prob_ab(fun, abest, prob, domain)
return(c(abest,b))
}
现在像这样使用上面的代码。我使用了一个非常不对称的函数(只是假设我的dist实际上是一些复杂的pdf,而不是dgamma)。
mydist <- function(x)dgamma(x, shape=2)
curve(mydist(x), from=0, to=10)
abline(v=prob_int_shortest(mydist, 0.9, c(0,10)), lty=3, col="blue", lwd=2)
在这个例子中,我将区间设置为(0,10),因为显然区间必须在其中某个位置。请注意,使用像(0,1E05)这样的非常大的值是不起作用的,因为
integrate
在接近零的长序列上会出现问题。同样,对于您的情况,您需要调整域(除非有更好的想法!)。