(Поскольку этот подход не зависит от других опубликованных решений, в том числе от того, который я опубликовал, я предлагаю его в качестве отдельного ответа).
Вы можете вычислить точное распределение в секундах (или меньше) при условии, что сумма p мала.
Мы уже видели предположения о том, что распределение может быть приблизительно гауссовым (при некоторых сценариях) или пуассоновским (при других сценариях). В любом случае, мы знаем, что его среднее значение является суммой p i, а его дисперсия σ 2 является суммой p i ( 1 - p i ) . Поэтому распределение будет сконцентрировано в пределах нескольких стандартных отклонений от его среднего значения, скажем, z SD с z между 4 и 6 или около того. Поэтому нам нужно только вычислить вероятность того, что сумма X равна (целому числу) k для k = -μpiσ2pi(1−pi)zzXk через k = μ + z σ . Когда большая часть p i мала, σ 2 приблизительно равна (но немного меньше) μ , поэтому, чтобы быть консервативным, мы можем выполнить вычисление для k в интервале [ μ - z √k=μ−zσk=μ+zσpiσ2μk. Например, когда суммаpiравна9и выбранz=6, чтобы хорошо покрыть хвосты, нам понадобится вычисление для покрытияkв[9-6 √[μ−zμ−−√,μ+zμ−−√]pi9z=6k=[0,27], что составляет всего 28 значений.[9−69–√,9+69–√][0,27]
Распределение вычисляется рекурсивно . Пусть - распределение суммы первых i этих переменных Бернулли. Для любого j от 0 до i + 1 сумма первых переменных i + 1 может равняться j двумя взаимоисключающими способами: сумма первых переменных i равна j, а i + 1 st равна 0, иначе сумма первые переменные я равен J - 1 иfiij0i+1i+1jiji+1st0ij−1 это 1 . Следовательноi+1st1
fi+1(j)=fi(j)(1−pi+1)+fi(j−1)pi+1.
Нам нужно только выполнить это вычисление для интеграла в интервале от max ( 0 , μ - z √j доμ+z √max(0,μ−zμ−−√) μ+zμ−−√.
Когда большинство крошечные (но 1 - p i по-прежнему отличимы от 1 с разумной точностью), этот подход не страдает от огромного накопления ошибок округления с плавающей запятой, используемых в ранее опубликованном решении. Следовательно, вычисления с расширенной точностью не требуются. Например, расчет с двойной точностью для массива из 2 16 вероятностей p i = 1 / ( i + 1 ) ( μ = 10,6676 , требующий вычислений для вероятностей сумм между 0pi1−pi1216pi=1/(i+1)μ=10.66760и ) потребовалось 0,1 секунды с Mathematica 8 и 1-2 секунды с Excel 2002 (оба получили одинаковые ответы). Повторяя его с четырехкратным точностью (в Mathematica) занимает около 2 -х секунд , но не изменил ни одного ответа на более чем 3 × 10 - 15 . Прекращение распределения при z = 6 SD в верхний хвост потеряло только 3,6 × 10 - 8 от общей вероятности.313×10−15z=63.6×10−8
Другое вычисление для массива из 40000 случайных значений двойной точности между 0 и 0,001 ( ) заняло 0,08 секунды с Mathematica.μ=19.9093
Этот алгоритм распараллеливается. Просто разбейте множество на непересекающиеся подмножества примерно одинакового размера, по одному на процессор. Вычислите распределение для каждого подмножества, затем сверните результаты (используя FFT, если хотите, хотя это ускорение, вероятно, не нужно), чтобы получить полный ответ. Это делает его практичным для использования, даже когда μ становится большим, когда вам нужно смотреть далеко в хвосты ( z большое), и / или n большое.piμzn
Время для массива из переменных с m процессорами масштабируется как O ( n ( μ + z √nm. Скорость Mathematica составляет порядка миллиона в секунду. Например, припроцессореm=1,n=20000изменяется, общая вероятностьμ=100, а выход наz=6стандартных отклонений в верхнем хвосте,n(μ+z √O(n(μ+zμ−−√)/m)m=1n=20000μ=100z=6миллиона: цифра в пару секунд вычислительного времени. Если вы скомпилируете это, вы можете увеличить производительность на два порядка.n(μ+zμ−−√)/m=3.2
Между прочим, в этих тестовых случаях графики распределения ясно показали некоторую положительную асимметрию: они не являются нормальными.
Для справки, вот решение 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 . Цветовое кодирование, примененное этим сайтом, не имеет смысла для кода Mathematica. В частности, серый материал - это не комментарии: это то, где вся работа сделана!)
Примером его использования является
pb[RandomReal[{0, 0.001}, 40000], 8]
редактировать
R
Решение в десять раз медленнее , чем Mathematica в этом тесте - возможно , я не закодировал оптимально - но он по- прежнему выполняет быстро (около одной секунды):
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)