(Poiché questo approccio è indipendente dalle altre soluzioni pubblicate, inclusa una che ho pubblicato, lo offro come risposta separata).
Puoi calcolare l'esatta distribuzione in secondi (o meno) purché la somma delle p sia piccola.
Abbiamo già visto dei suggerimenti secondo cui la distribuzione potrebbe essere approssimativamente gaussiana (in alcuni scenari) o Poisson (in altri scenari). Ad ogni modo, sappiamo che la sua media è la somma di p i e la sua varianza σ 2 è la somma di p i ( 1 - p i ) . Pertanto, la distribuzione sarà concentrata all'interno di alcune deviazioni standard della sua media, ad esempio z SD con z tra 4 e 6 o giù di lì. Pertanto, dobbiamo solo calcolare la probabilità che la somma X sia uguale (un numero intero) k per k = μμpiσ2pi(1−pi)zzXk a k = μ + z σ . Quando la maggior parte di p i è piccola, σ 2 è approssimativamente uguale a (ma leggermente inferiore a) μ , quindi per essere conservativi possiamo fare il calcolo per k nell'intervallo [ μ - z √k=μ−zσk=μ+zσpiσ2μk. Ad esempio, quando la somma delpiè uguale a9e scegliendoz=6per coprire bene le code, sarebbe necessario il calcolo di coperturakin[9-6 √[μ−zμ−−√,μ+zμ−−√]pi9z=6k=[0,27], che è solo 28 valori.[9−69–√,9+69–√][0,27]
La distribuzione viene calcolata in modo ricorsivo . Permettetemi di essere la distribuzione della somma della prima I di queste variabili di Bernoulli. Per qualsiasi j compreso tra 0 e i + 1 , la somma delle prime variabili i + 1 può eguagliare j in due modi reciprocamente esclusivi: la somma delle prime i variabili è uguale a j e i + 1 st è 0 oppure la somma di la prima variabile i è uguale a j - 1 e lafiij0i+1i+1jiji+1st0ij−1 è 1 . Perciòi+1st1
fi+1(j)=fi(j)(1−pi+1)+fi(j−1)pi+1.
Dobbiamo solo eseguire questo calcolo per integrale nell'intervallo da max ( 0 , μ - z √j aμ+z √max(0,μ−zμ−−√) μ+zμ−−√.
Quando la maggior parte della sono minuscole (ma il 1 - p io sono ancora distinguibili dal 1 con ragionevole precisione), questo approccio non è afflitto con l'enorme accumulo di virgola mobile arrotondamento errori utilizzati nella soluzione ho già postato. Pertanto, non è richiesto il calcolo con precisione estesa. Ad esempio, un calcolo a doppia precisione per un array di 2 16 probabilità p i = 1 / ( i + 1 ) ( μ = 10.6676 , che richiede calcoli per probabilità di somme comprese tra 0pi1−pi1216pi=1/(i+1)μ=10.66760e ) ha impiegato 0,1 secondi con Mathematica 8 e 1-2 secondi con Excel 2002 (entrambi hanno ottenuto le stesse risposte). Ripetendo con precisione quadrupla (in Mathematica) sono voluti circa 2 secondi, ma non ha cambiato alcuna risposta da più di 3 × 10 - 15 . Terminare la distribuzione a z = 6 SD nella coda superiore ha perso solo 3,6 × 10 - 8 della probabilità totale.313×10−15z=63.6×10−8
Un altro calcolo per un array di 40.000 valori casuali a doppia precisione tra 0 e 0,001 ( ) ha richiesto 0,08 secondi con Mathematica.μ=19.9093
Questo algoritmo è parallelizzabile. Basta rompere l'insieme di in sottoinsiemi disgiunti di approssimativamente uguale dimensione, uno per processore. Calcola la distribuzione per ciascun sottoinsieme, quindi contorta i risultati (usando FFT se vuoi, anche se questa velocità probabilmente non è necessaria) per ottenere la risposta completa. Questo rende pratico l'uso anche quando μ diventa grande, quando è necessario guardare lontano nelle code ( z grande) e / o n è grande.piμzn
I tempi per una matrice di variabili con processori m vengono ridimensionati come O ( n ( μ + z √nm. La velocità di Mathematica è dell'ordine di un milione al secondo. Ad esempio, conm=1processore,n=20000variate, una probabilità totale diμ=100e andando az=6deviazioni standard nella coda superiore,n(μ+z √O(n(μ+zμ−−√)/m)m=1n=20000μ=100z=6milioni: calcola un paio di secondi di tempo di calcolo. Se lo compili, potresti accelerare le prestazioni di due ordini di grandezza.n(μ+zμ−−√)/m=3.2
Per inciso, in questi casi di test, i grafici della distribuzione mostravano chiaramente un'asimmetria positiva: non sono normali.
Per la cronaca, ecco una soluzione 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 La codifica a colori applicata da questo sito non ha senso per il codice Mathematica. In particolare, la roba grigia non è commenti: è dove tutto il lavoro è fatto!)
Un esempio del suo utilizzo è
pb[RandomReal[{0, 0.001}, 40000], 8]
modificare
Una R
soluzione è dieci volte più lenta di Mathematica in questo caso di test - forse non l'ho codificata in modo ottimale - ma viene comunque eseguita rapidamente (circa un secondo):
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)