Случайный выбор из списка со взвешенными вероятностями

У меня есть массив из N элементов (представляющих N букв данного алфавита), и каждая ячейка массива содержит целое значение, которое означает количество вхождений в данном тексте этой буквы. Теперь я хочу случайным образом выбрать букву из всех букв алфавита, основываясь на его количестве появлений с заданными ограничениями:

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

  • Если буква A имеет большее значение, чем буква B, то она должна быть с большей вероятностью выбрана алгоритмом.

теперь, принимая это во внимание, я придумал простой алгоритм, который может выполнить эту работу, но мне просто интересно, есть ли что-то лучше. Это кажется довольно фундаментальным, и я думаю, что могут быть более умные вещи, чтобы сделать это более эффективный. Это алгоритм, который я думал:

  • добавить все частоты в массиве. Храните его в SUM
  • выбор случайного значения от 0 до суммы. Храните его в RAN
  • [While] RAN > 0, начиная с первого, посетите каждую ячейку в массиве (по порядку) и вычитайте значение этой ячейки из RAN
  • последняя посещенная ячейка является выбранной

Итак, есть ли что-то лучше, чем это? Я скучаю? что-то?

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

Я предпочитаю объясненный алгоритм, а не просто код для ответа, но если вам удобнее предоставить свой ответ в коде, у меня нет проблем с этим.

2 ответов


идея:

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

пример:

Element    A B C D
Frequency  1 4 3 2
Cumulative 1 5 8 10

генерировать случайное число в диапазоне 1-10 (1+4+3+2 = 10, то же, что и последнее значение в накопительном списке), выполните двоичный поиск, который вернет значения следующим образом:

Number   Element returned
1        A
2        B
3        B
4        B
5        B
6        C
7        C
8        C
9        D
10       D

на Метод Псевдоним амортизировал O (1) Время на генерируемое значение, но требует двух униформ на поиск. В принципе, вы создаете таблицу, где каждый столбец содержит одно из создаваемых значений, второе значение, называемое псевдонимом, и условную вероятность выбора между значением и его псевдонимом. Используйте свою первую униформу, чтобы выбрать любой из столбцов с равной вероятностью. Затем выберите между основным значением и псевдонимом на основе вашей второй униформы. Требуется O(n log n) сначала настройте допустимую таблицу для n значений, но после того, как построенные генерирующие значения таблицы являются постоянным временем. Вы можете скачать этот рубиновый камень чтобы увидеть фактическую реализацию.

два других очень быстрых метода Марсалья и др. описаны здесь. Они предоставили реализации C.