Случайный выбор из списка со взвешенными вероятностями
У меня есть массив из 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.