Случайные числа с неравномерной дискретной плотностью

#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;
}