目前尚不清楚“灭绝风险类别”的含义,但似乎问题要求计算具有给定期望的 15 个独立二项式变量之和的分布。这是一个卷积,使用快速傅里叶变换最有效。
这是 中的一个示例R
,其convolve
函数使用 FFT:
x <- c(0.17,0.46,0.62,0.08,0.40,0.76,0.03,0.47,0.53,0.32,0.21,0.85,0.31,0.38,0.69)
z <- 1
for (u in sort(x)) z <- convolve(z, c(u, 1-u), type="open")
z
[1] 5.826e-05 1.069e-03 8.233e-03 3.566e-02 9.775e-02 1.805e-01 2.324e-01 2.128e-01
[9] 1.395e-01 6.520e-02 2.142e-02 4.800e-03 6.979e-04 6.039e-05 2.647e-06 4.091e-08
作为检查,在Mathematica中获得了相同的结果
Product[1 - z + z t, {z, x}] // Expand
4.091095×10−8t15+2.647052×10−6t14+⋯+0.0010688t+0.0000582614
现在,例如,机会10或更少的中毒计算R
为
sum(z[1:11])
[1] 0.9944
编辑
对于较大的问题,使用R
'convolve
函数效率低下,因为它反复执行 FFT 及其逆运算。事实证明,直接卷积算法——正如 StasK 所描述的——足够快。这是一个R
实现。
convolve.binomial <- function(p) {
# p is a vector of probabilities of Bernoulli distributions.
# The convolution of these distributions is returned as a vector
# `z` where z[i] is the probability of i-1, i=1, 2, ..., length(p)+1.
n <- length(p) + 1
z <- c(1, rep(0, n-1))
for (p in p) z <- (1-p)*z + p*c(0, z[-n])
return(z)
}
(感谢一位匿名编辑提出的改进以阐明算法。)
这需要O(n2)的时间n分布——二次行为不好——但它仍然相当快。例如,让我们生成 10,000 个随机概率(而不是使用 15 个给定的概率)并形成相应伯努利分布的卷积:
x <- runif(10000)
system.time(y <- convolve.binomial(x))
这仍然需要不到 3 秒的时间。