Выбор случайного элемента на основе вероятностей - PullRequest
7 голосов
/ 05 мая 2010

Есть похожий вопрос , я знаю, но это смутило меня, поэтому я подумал, что мне проще спросить на моем пути.

Итак, у меня есть массив значений, положительных и отрицательных. Чем они выше, тем больше вероятность, что их выберут.
У меня проблемы с тем, чтобы понять, как назначить вероятности, а затем случайным образом выбрать одну. Я предполагаю, что сначала нужно отсортировать массив, но потом я немного растерялся.

Ответы [ 3 ]

23 голосов
/ 05 мая 2010

«У меня разные чашки кофе разных размеров. Чем они больше, тем больше я хочу взимать с них плату. У меня возникают проблемы с определением, как назначать цены».

Это не просто проблема программирования - вы указали, что вероятность увеличивается со значением, но вы не сказали, как увеличивается со значением. Как правило, в кофейнях плата не взимается прямо пропорционально количеству кофе. Вы не можете назначить вероятности пропорционально значению, потому что некоторые из ваших значений отрицательны, но вероятности не могут быть отрицательными.

Звучит так, как будто вам нужно еще немного прибить проблему, прежде чем вы сможете написать какой-либо код.

Если вам действительно все равно, как вероятность соотносится со значением, кроме того, что они увеличиваются в порядке значения, то одним простым способом будет:

  • сортировка вашего массива
  • присвойте вероятности 1 первому элементу, 2 второму и т. Д.
  • Теперь ваши вероятности не составляют 1, что является проблемой. Поэтому разделите каждую вероятность на сумму всех назначенных вами вероятностей: (1 + 2 + .. + n) = n(n+1)/2. Это называется "нормализация".

Учитывая ваш список вероятностей, который в сумме составляет 1, самый простой способ повторно выбрать одну из них, как правило, рассчитать совокупные вероятности , которые я продемонстрирую на примере:

value (sorted):           -12     -3      127    1000000
assigned probability:     0.1     0.2     0.3      0.4
cumulative probability:   0.1     0.3     0.6      1.0

Совокупная вероятность определяется как сумма всех вероятностей до этой точки.

Теперь, из вашего генератора случайных чисел вам нужно случайное (с плавающей запятой) значение в диапазоне от 0 до 1. Если оно лежит в диапазоне от 0 до 0,1, вы выбрали -12. Если он лежит между 0,1 и 0,3, вы выбрали -3 и так далее. Чтобы выяснить, в каком диапазоне он находится, вы можете линейно пройти по массиву или выполнить бинарный поиск.

Вы можете пропустить шаг нормализации и использование плавающей запятой, если хотите. Назначьте «кумулятивные вероятности» (1, 3, 6, 10 ...), но сделайте понятным, что фактическая вероятность - это сохраненное целочисленное значение, деленное на n (n + 1) / 2. Затем выберите случайное целое число от 0 до n (n + 1) / 2 - 1. Если оно меньше 1, вы выбрали первое значение, иначе, если меньше 3, второе и т. Д. Это может или не может сделать код более понятным, и ваш RNG может или не может делать выбор целочисленных значений из большого диапазона.

Обратите внимание, что вы могли назначить вероятности (0,001, 0,002, 0,003, 0,994) вместо (0,1, 0,2, 0,3, 0,4) и по-прежнему удовлетворять вашему требованию, что «чем выше значение, тем выше вероятность».

2 голосов
/ 05 мая 2010

Один путь может быть

  • Сделать все значения положительными (добавить абсолютное значение минимального значения ко всем значениям)
  • Нормализовать значения для суммирования 1 (разделить каждое значение на сумму значений)

Чтобы рандомизировать значение из сгенерированного распределения теперь вы можете

  • Выберите случайное число на [0,1].
  • Начните суммировать вероятности, пока сумма не станет больше или равна случайному значению. Выберите этот индекс в качестве случайного значения.
1 голос
/ 02 ноября 2011

Следуя предложению Стива Джессопа, после того, как вы выбрали случайное целое число от 0 до n (n + 1) / 2 - 1, вы можете просто получить треугольный корень: (-1 + sqrt ((8 * x) ) +1)) / 2 * +1001 *

...