(Dado que este enfoque es independiente de las otras soluciones publicadas, incluida una que yo he publicado, lo ofrezco como una respuesta separada).
Se puede calcular la distribución exacta en segundos (o menos) siempre que la suma de las p sea pequeña.
Ya hemos visto sugerencias de que la distribución podría ser aproximadamente gaussiana (en algunos escenarios) o de Poisson (en otros escenarios). En cualquier caso, sabemos que su media $\mu$ es la suma de los $p_i$ y su varianza $\sigma^2$ es la suma de $p_i(1-p_i)$ . Por lo tanto, la distribución se concentrará dentro de unas pocas desviaciones estándar de su media, digamos $z$ SDs con $z$ entre 4 y 6 o más. Por lo tanto, sólo tenemos que calcular la probabilidad de que la suma $X$ es igual a (un número entero) $k$ para $k = \mu - z \sigma$ a través de $k = \mu + z \sigma$ . Cuando la mayoría de los $p_i$ son pequeños, $\sigma^2$ es aproximadamente igual (pero ligeramente inferior) a $\mu$ por lo que, para ser conservadores, podemos hacer el cálculo para $k$ en el intervalo $[\mu - z \sqrt{\mu}, \mu + z \sqrt{\mu}]$ . Por ejemplo, cuando la suma de los $p_i$ es igual a $9$ y elegir $z = 6$ para cubrir bien las colas, necesitaríamos que el cómputo cubriera $k$ en $[9 - 6 \sqrt{9}, 9 + 6 \sqrt{9}]$ = $[0, 27]$ , que son sólo 28 valores.
La distribución se calcula recursivamente . Sea $f_i$ sea la distribución de la suma de los primeros $i$ de estas variables Bernoulli. Para cualquier $j$ de $0$ a través de $i+1$ la suma de la primera $i+1$ las variables pueden ser iguales a $j$ de dos maneras mutuamente excluyentes: la suma del primer $i$ variables es igual a $j$ y el $i+1^\text{st}$ es $0$ o bien la suma del primer $i$ variables es igual a $j-1$ y el $i+1^\text{st}$ es $1$ . Por lo tanto,
$$f_{i+1}(j) = f_i(j)(1 - p_{i+1}) + f_i(j-1) p_{i+1}.$$
Sólo tenemos que realizar este cálculo para la integral $j$ en el intervalo de $\max(0, \mu - z \sqrt{\mu})$ a $\mu + z \sqrt{\mu}.$
Cuando la mayoría de los $p_i$ son diminutos (pero el $1 - p_i$ siguen siendo distinguibles de $1$ con una precisión razonable), este enfoque no está plagado de la enorme acumulación de errores de redondeo en coma flotante utilizados en la solución que publiqué anteriormente. Por lo tanto, no es necesario el cálculo de precisión extendida. Por ejemplo, un cálculo de doble precisión para un array de $2^{16}$ probabilidades $p_i = 1/(i+1)$ ( $\mu = 10.6676$ , requiriendo cálculos para las probabilidades de las sumas entre $0$ y $31$ ) tardó 0,1 segundos con Mathematica 8 y 1-2 segundos con Excel 2002 (ambos obtuvieron las mismas respuestas). Repetirlo con precisión cuádruple (en Mathematica) llevó unos 2 segundos pero no cambió ninguna respuesta en más de $3 \times 10^{-15}$ . Terminar la distribución en $z = 6$ Los SD en la cola superior sólo perdieron $3.6 \times 10^{-8}$ de la probabilidad total.
Otro cálculo para una matriz de 40.000 valores aleatorios de doble precisión entre 0 y 0,001 ( $\mu = 19.9093$ ) tardó 0,08 segundos con Mathematica.
Este algoritmo es paralelizable. Sólo hay que romper el conjunto de $p_i$ en subconjuntos disjuntos de tamaño aproximadamente igual, uno por procesador. Calcule la distribución de cada subconjunto y, a continuación, convolucione los resultados (utilizando la FFT si lo desea, aunque esta aceleración es probablemente innecesaria) para obtener la respuesta completa. Esto hace que sea práctico utilizarlo incluso cuando $\mu$ se hace grande, cuando hay que mirar lejos en las colas ( $z$ grande), y/o $n$ es grande.
El tiempo para una serie de $n$ variables con $m$ escalas de procesadores como $O(n(\mu + z \sqrt{\mu})/m)$ . La velocidad de Mathematica es del orden de un millón por segundo. Por ejemplo, con $m = 1$ procesador, $n = 20000$ variantes, una probabilidad total de $\mu = 100$ y salir a $z = 6$ desviaciones estándar en la cola superior, $n(\mu + z \sqrt{\mu})/m = 3.2$ millones: calcula un par de segundos de tiempo de cálculo. Si lo compilas, podrías acelerar el rendimiento dos órdenes de magnitud.
Por cierto, en estos casos de prueba, los gráficos de la distribución mostraban claramente cierta asimetría positiva: no son normales.
Para que conste, aquí hay una solución de Mathematica:
pb[p_, z_] := Module[
{\[Mu] = Total[p]},
Fold[#1 - #2 Differences[Prepend[#1, 0]] &,
Prepend[ConstantArray[0, Ceiling[\[Mu] + Sqrt[\[Mu]] z]], 1], p]
]
( NB El código de colores aplicado por este sitio no tiene sentido para el código de Mathematica. En particular, lo gris es no comentarios: ¡es donde se hace todo el trabajo!)
Un ejemplo de su uso es
pb[RandomReal[{0, 0.001}, 40000], 8]
Editar
Un R
es diez veces más lenta que Mathematica en este caso de prueba -quizás no lo he codificado de forma óptima- pero aún así se ejecuta rápidamente (alrededor de un segundo):
pb <- function(p, z) {
mu <- sum(p)
x <- c(1, rep(0, ceiling(mu + sqrt(mu) * z)))
f <- function(v) {x <<- x - v * diff(c(0, x));}
sapply(p, f); x
}
y <- pb(runif(40000, 0, 0.001), 8)
plot(y)