#random #non-uniform-distribution
#Случайный #неравномерное распределение
Вопрос:
Просто интересно, что это за алгоритм,
или есть ли более простой / эффективный способ сделать это:
Допустим, нам задана определенная плотность вероятности, скажем
prob[] = {.1, .15, .25, .05, .45}
Группа 1 — 10%
Группа 2 — 15%
Группа 3 — 25%
Группа 4 — 5%
Группа 5 — 45%
и случайное число, (0,1),
ran = .853234
Вставить в одну из 5 групп
if (ran <=prob[0]) selection = 1;
else if (ran <= prob[0] prob[1]) selection = 2;
...
else if (ran <= prob[0] prob[1] ... prob[4]) selection = 5;
Я не очень хорошо разбираюсь в генерации случайных чисел
Ответ №1:
То, что вы по сути делаете здесь, — это инвертирование кумулятивной функции распределения. Пусть F
— CDF случайной величины X
с заданным распределением, тогда она определяется как F(x) == P[X <= x]
.
Очень полезная вещь здесь заключается в том, что если вы генерируете однородную случайную величину U
между 0 и 1, то
P[F^-1(U) <= x] == P[U <= F(x)] == F(x) == P[X <= x]
это означает, что F^-1(U)
это будет иметь такое же распределение, как X
!
Конечно, это возможно только в том случае, если вы можете инвертировать CDF, но в вашем случае F
это кусочная функция (например, лестница), и ваш алгоритм определяет для заданного равномерного значения, на каком шаге выполняется это значение. Поэтому ваш алгоритм совершенно правильный.
Однако вы могли бы улучшить его, если у вас есть много случайных чисел для генерации: сначала создайте таблицу CDF, которая в вашем случае будет
CDF[] = {.1, .25, .5, .55, 1.}
затем для каждого сгенерированного однородного числа от 0 до 1 просто выполните дихотомию в таблице CDF, чтобы повторно преобразовать соответствующий индекс.
Ответ №2:
Ваш алгоритм верен. Однако в вашем примере вероятности не равны 1.
Ответ №3:
Этот код будет работать, за исключением того, что ваши вероятности не составляют 100% (поэтому ни один из операторов if не может совпадать).
Подход можно немного упростить, используя кумулятивное распределение вероятностей:
cumprob[5] = {.1, .2, .45, .50, 1.0};
Это также позволяет заменить цепочку if-elif на lsearch.
Ответ №4:
Ваш алгоритм использует случайные числа с плавающей запятой для дискретного распределения, что не является лучшим способом реализации этого. Ваша реализация может обеспечить распределение, едва отличимое от данного распределения, но это неверно с научной точки зрения.
Вместо этого найдите наименьший общий знаменатель ваших заданных вероятностей (в вашем примере 5%) и используйте случайное целое число в [0,19], чтобы выбрать свою группу. Пример:
switch(random(19)) {
case 0:
case 1:
selection = 1;
break;
case 2:
case 3:
case 4:
selection = 2;
break;
case 5:
case 6:
case 7:
case 8:
case 9:
selection = 3;
break;
case 10:
selection = 4;
break;
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
selection = 4;
break;
}