(Оскільки цей підхід не залежить від інших розміщених рішень, включаючи те, що я опублікував, я пропоную це як окрему відповідь).
Ви можете обчислити точний розподіл у секундах (або менше) за умови невеликої суми р.
Ми вже бачили припущення, що розподіл може бути приблизно гауссовим (за деякими сценаріями) або пуассонським (за інших сценаріїв). Так чи інакше, ми знаємо, що його середнє - сума 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- й дорівнює 0, інакше сума перша змінна i дорівнює j - 1 і thefiij0i+1i+1jiji+1st0ij−1 - 1 . Томуi+1st1
fi + 1( j ) = fi( j ) ( 1 - сi + 1) + fi( j - 1 ) сi + 1.
Нам потрібно лише провести це обчислення для інтеграла в інтервалі від max ( 0 , μ - z √j доμ+z √max ( 0 , μ - zмк--√) μ + zмк--√.
Коли більшість є крихітними (але 1 - p i все ще відрізняються від 1 з розумною точністю), цей підхід не зазнає величезного накопичення помилок округлення з плаваючою точкою, використовуваних у попередньому розміщенні рішення. Тому розрахунки з розширеною точністю не потрібні. Наприклад, обчислення подвійної точності для масиву 2 16 ймовірностей p i = 1 / ( i + 1 ) ( μ = 10,6676 , що вимагає обчислення ймовірностей сум між 0pi1 - сi1216pi= 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]
]
( Примітка . Кольорове кодування, застосоване на цьому веб-сайті, не має сенсу для коду 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)