Як генерувати числа на основі довільного дискретного розподілу?


28

Як генерувати числа на основі довільного дискретного розподілу?

Наприклад, у мене є набір чисел, які я хочу створити. Скажіть, вони позначені від 1-3 так.

1: 4%, 2: 50%, 3: 46%

В основному відсотки - це ймовірність того, що вони з'являться у висновку з генератора випадкових чисел. У мене є генератор песових випадкових чисел, який генеруватиме рівномірний розподіл в інтервалі [0, 1]. Чи є спосіб це зробити?

Немає меж, скільки я можу мати елементів, але% додасть до 100%.


2
Я б запропонував вказати в заголовку "... довільні дискретні розподіли", якщо це ваше питання. Суцільний випадок різний.
David M Kaplan

3
Узагальненим способом є здійснення двійкового пошуку в списку сукупних ймовірностей, який у цьому прикладі був би (0,0.04,0.54,1.0) . В середньому це займає log(n)/2 зонди на покоління події. Якщо ймовірність надзвичайно мала, ви можете отримати продуктивність O(1) , створивши вектор з однаково розташованими значеннями в [0,1] та (на етапі попереднього обчислення), призначивши результат кожному значенню. Наприклад, у цьому прикладі ви можете створити вектор (1,1,1,1,2,,2,3,,3)50 2 та 46 3's). Створіть рівномірне, помножте на 100 та індексуйте на цей вектор: зроблено.
качан

Також дивіться тут
Glen_b -Встановіть Моніку

Це посилання "тут" насправді посилається на саме це запитання, @Glen_b ... помилка копіювання-n-вставки?
buruzaemon

@buruzaemon дякую так, це була помилка; Я це виправив.
Glen_b -Встановіть Моніку

Відповіді:


26

Одним з найкращих алгоритмів вибірки з дискретного розподілу є метод псевдоніму .

Метод псевдоніму (ефективно) попередньо обчислює двовимірну структуру даних для розподілу прямокутника на області, пропорційні ймовірності.

Малюнок

У цій схемі із посиланого сайту прямокутник одиничної висоти був розподілений на чотири види регіонів - як диференційовані за кольором - у пропорціях , , та , у щоб повторно відібрати вибірку з дискретного розподілу з цими ймовірностями. Вертикальні смуги мають постійну (одиничну) ширину. Кожна поділяється лише на одну-дві частини. Ідентичності фрагментів та місця вертикальних поділів зберігаються в таблицях, доступних через індекс стовпців.1 / 3 1 / 12 1 / 121/21/31/121/12

Таблиця може бути вибірковою в два простих етапи (по одному для кожної координати), що вимагає генерувати лише два незалежних рівномірних значення та обчислення . Це покращує обчислення необхідні для інвертування дискретного CDF, як описано в інших відповідях тут.O ( log ( n ) )O(1)O(log(n))


2
Цей алгоритм найкращий, лише якщо ймовірності дешеві для обчислення. Наприклад, якщо величезна, можливо, краще не будувати все дерево. n
ймовірністьлогічний

3
+1 На даний момент це єдина відповідь, яка дозволяє запропонувати та описати ефективний алгоритм.
whuber

19

Це легко зробити в R, просто вкажіть потрібний вам розмір:

sample(x=c(1,2,3), size=1000, replace=TRUE, prob=c(.04,.50,.46))

3
Особисто я б віддав перевагу алгоритму (або десь, щоб засвоїти необхідні знання), оскільки я намагаюся включити це в додаток, який будую :) Хоча велике спасибі за вашу відповідь :)
FurtiveFelon

Гммм добре ... Знання трохи більше про те, що ви хочете зробити, допомогло б нам направити вас. Чи можете ви розповісти нам більше про це? (Призначення, контекст тощо)
Домінік Комтуа

Це для голосування. Наприклад, у мене є маса фотографій, і я можу показувати лише користувачеві 6 за один раз, я хотів би включити "найкраще" для користувача одночасно, і користувач може проголосувати вгору або вниз за кожну фотографію . Найпростішим рішенням, яке могло б працювати зараз, є схема, яку я окреслив (кожен номер представляє фотографію, кожен голос вниз зменшить ймовірність цієї фотографії та збільшиться на все інше)
FurtiveFelon

1
@furtivefelon, ви завжди можете перенести код з R, o з'ясувати алгоритм з коду і повторно його доповнити.
mpiktas

Я думаю, ви можете отримати хорошу (кращу) пораду щодо Stack Overflow, оскільки, ймовірно, існує кілька відомих рішень для цієї конкретної мети. Я пропоную також включити інформацію з вашого останнього коментаря безпосередньо у ваше запитання.
Домінік Комтуа

19

У своєму прикладі скажіть, що ви малюєте своє псевдовипадкове Уніфіковане [0,1] значення і називаєте його U. Потім виведіть:

1, якщо U <0,04

2, якщо U> = 0,04 і U <0,54

3, якщо U> = 0,54

Якщо вказані% є a, b, ..., просто виведіть

значення 1, якщо U

значення 2, якщо U> = a і U <(a + b)

тощо.

По суті, ми відображаємо% у підмножини [0,1], і ми знаємо ймовірність того, що рівномірне випадкове значення потрапляє в будь-який діапазон - це просто довжина цього діапазону. Впорядкування діапазонів здається найпростішим, якщо не унікальним способом. Це припущення, що ви запитуєте лише про дискретні розподіли; безперервно, може зробити щось на кшталт "відбору проб відхилення" ( запис у Вікіпедії ).


8
Алгоритм швидший, якщо ви сортуєте категорії у порядку зменшення ймовірності. Таким чином, ви робите менше тестів (в середньому) на кожне генероване випадкове число.
jbowman

1
Просто додати швидку примітку про сортування - це буде ефективно лише в тому випадку, якщо ви будете робити це один раз на початку схеми вибірки - тому це не буде добре для випадків, коли самі ймовірності відібрані як частина більшої загальної схеми ( наприклад, а потім ). Сортуючи в цьому випадку, ви додаєте операцію сортування до кожної ітерації вибірки - що додасть час до кожної ітерації. Однак у цьому випадку може бути корисним сортування за приблизною здогадкою за розміром ймовірностей на початку. pjDistPr(Y=j)=pjO(nlog(n))
ймовірністьлогічний

4

Припустимо, є можливих дискретних результатів. Ви поділяєте інтервал на підінтервали на основі функції кумулятивної маси ймовірностей, , щоб дати розділений інтервалm[0,1]F(0,1)

I1I2Im

де і . У вашому прикладі іIj=(F(j1),F(j))F(0)0m=3

I1=(0,.04),     I2=(.04,.54),     I3=(.54,1)

оскільки і і .F(1)=.04F(2)=.54F(3)=1

Тоді ви можете генерувати з розподілом використовуючи наступний алгоритм:XF

(1) генеруватиUUniform(0,1)

(2) Якщо , то .UIjX=j

  • Цей крок можна здійснити, переглянувши, чи менше менше кожної із сукупних ймовірностей, і побачити, де відбувається точка зміни (від до ), що має бути проблемою використання булевого оператора в будь-якій мові програмування, яку ви використовуєте та знаходження, де перше відбувається у векторі.UTRUEFALSEFALSE

Зауважте, що буде знаходитись точно в одному з інтервалів оскільки вони неперервні та перегородки .UIj[0,1]


Чи не повинні ці інтервали бути напівзакритими? Інакше межі між інтервалами не включаються .. тобто. {[0,0.04), [0.04,0.54), [0.54,1]}
ніщо101

1
P(U=u)=0 для будь-якої точки (тобто міра Лебега напіввідкритого інтервалу така ж, як і для відкритого інтервалу), тому я не думаю, що це має значення. u
Макрос

1
На цифровій машині з обмеженою точністю, хоча, можливо, колись до кінця Всесвіту це матиме значення ...
jbowman

1
Досить справедливо, @whuber, дивись мою редакцію.
Макрос

1
Гаразд, це алгоритм. До речі, чому ти просто не повернеш щось подібне min(which(u < cp))? Було б добре уникати перерахунку сукупної суми за кожним викликом. З цим попередньо обчисленим, весь алгоритм зводиться до min(which(runif(1) < cp)). Або ще краще, тому що ОП просить генерувати числа ( множину ), векторизувати його як n<-10; apply(matrix(runif(n),1), 2, function(u) min(which(u < cp))).
whuber

2

Один простий алгоритм - почати з вашого рівномірного випадкового числа і в циклі спочатку відняти першу ймовірність, якщо результат негативний, то ви повернете перше значення, якщо все-таки додатне, то переходите до наступної ітерації та віднімаєте наступну ймовірність , перевірте, чи немає негативу тощо.

Це приємно тим, що кількість значень / ймовірностей може бути нескінченною, але вам потрібно розраховувати ймовірності лише тоді, коли ви наближаєтесь до цих чисел (для чогось, наприклад, генерування Пуассона чи негативного біноміального розподілу).

Якщо у вас є кінцевий набір ймовірностей, але ви будете генерувати з них багато чисел, то може бути ефективніше сортувати ймовірності так, щоб ви віднімали найбільше перше, потім друге найбільше наступне і так далі.


2

Перш за все, дозвольте звернути вашу увагу на бібліотеку пітонів з готовими до використання класами для генерування випадкових чисел з цілою чи плаваючою точкою, які слідують за довільним розподілом.

Взагалі, існує декілька підходів до цієї проблеми. Деякі з них є лінійними за часом, але потребують великого обсягу пам’яті, деякі працюють за O (n log (n)) часу. Деякі оптимізовані для цілих чисел, а деякі визначені для кругових гістограм (наприклад: генерування випадкових часових плям протягом дня). У вищезгаданій бібліотеці я використовував цей документ для випадків цілих чисел і цей рецепт для чисел з плаваючою комою. У нього (як і раніше) бракує кругової підтримки гістограми і, як правило, безладно, але він працює добре.


2

У мене була така ж проблема. Враховуючи набір, де кожен елемент має ймовірність і чиї ймовірності елементів дорівнюють одному, я хотів ефективно зробити вибірку, тобто не сортуючи нічого і не повторюючи повторення набору .

Наступна функція малює найнижчу з рівномірно розподілених випадкових чисел в інтервалі . Нехай - випадкове число з .N[a,1)r[0,1)

next(N,a)=1(1a)rN

За допомогою цієї функції можна намалювати висхідний ряд з рівномірно розподілених випадкових чисел у [0,1). Ось приклад з :(ai)NN=10

a0=next(10,0)
a1=next(9,a0)
a2=next(8,a1)

a9=next(1,a8)

Малюючи цей висхідний ряд рівномірно розподілених чисел, повторіть набір ймовірностей який представляє ваш арбітражний (поки скінченний) розподіл. Нехайбути итератор і . Після малювання , збільшення нулю або більше разів, поки . Потім додайте до свого зразка і продовжуйте малювати .(ai)P0k<|P|pkPaikp0pk>aipkai+1


Приклад із набором оп та розміром вибірки :{(1,0.04),(2,0.5),(3,0.46)}N=10

i a_i k Намалюй суму
0 0,031 0 0,04 1
1 0.200 1 0,54 2
2 0,236 1 0,54 2
3 0.402 1 0.54 2
4 0,488 1 0,54 2
5 0,589 2 1,0 3
6 0,625 2 1,0 3
7 0,638 2 1,0 3
8 0,738 2 1,0 3
9 0,942 2 1,0 3

Зразок:(1,2,2,2,2,3,3,3,3,3)


Якщо вам цікаво функцію : це обернена ймовірність того, що одне з рівномірно розподілених випадкових чисел лежить в інтервалі з .nextN[a,x)x1


Здається, проблема, з якою ви звертаєтесь до різко зміненої у другому абзаці, з тієї, що вибірки від довільного дискретного розподілу до вибірки з рівномірного розподілу. Її рішення, мабуть, не відповідає питанням, яке тут було задано.
whuber

Я уточнив останню частину.
casi

Ваша відповідь все ще здається не пов'язаною з питанням. Не могли б ви навести невеликий, але нетривіальний приклад вашого алгоритму? Покажіть нам, як це створило б один малюнок із множини відповідно до ймовірностей, наведених у питанні. {1,2,3}
whuber

Я додав приклад. Моя відповідь має щось спільне з відповіддю Девіда М Каплана ( stats.stackexchange.com/a/26860/93386 ), але потрібна лише одна замість N (= розмір вибірки) ітерацій над безліччю, за рахунок малювання N N- го коріння. Я профілював обидві процедури, і моя пройшла набагато швидше.
casi

Дякую за роз’яснення (+1). Багатьом читачам може бути цікаво, що це не проста випадкова вибірка, оскільки результати з'являються у заздалегідь визначеному фіксованому порядку: до результатів потрібно застосувати випадкову перестановку, щоб створити просту випадкову вибірку. Можливо, вас також зацікавить паралелізована версія цього алгоритму, в якій де - простий випадковий зразок уніфікованих (0,1] u1,,uN+1
aj=i=1jlog(ui)i=1N+1log(ui)
u1,,uN+1
змінних
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.