Если вы хотите образец элементов без замены , у вас есть множество вариантов.
- Используйте алгоритм взвешенного выбора с заменой (например,
WeightedChoice
ниже ) для выбора случайных индексов. Каждый раз, когда выбирается индекс, устанавливайте вес для выбранного индекса на 0, чтобы он не выбирался снова. Или ... - Присвойте каждому индексу экспоненциально распределенное случайное число (со скоростью, равной весу этого индекса), составьте список пар, присваивающих каждое число индексу, затем отсортируйте этот список по этим числам. Затем возьмите каждый предмет от первого до последнего. Обратите внимание, что наивный способ сгенерировать случайное число,
-ln(1-RNDU01())/weight
, не является надежным (« Индекс неоднородных распределений » в разделе «Экспоненциальное распределение»). - Tim Виейра приводит дополнительные параметры в своем блоге.
- A статья Брэма ван де Клундерт сравнивает различные алгоритмы.
EDIT (август. 19): Обратите внимание, что для этих решений вес показывает, насколько вероятно, что данный элемент появится первым в образце. Этот вес не обязательно является вероятностью того, что данная выборка из n элементов будет включать этот элемент (то есть, вероятность включения ). Приведенные выше методы не обязательно гарантируют, что данный предмет появится в случайной выборке с вероятностью, пропорциональной его весу; для этого см. « Алгоритмы выборки с равными или неравными вероятностями ».
Предыдущий пост:
Предполагая, что вы хотите выбирать элементы случайным образом с заменой, вот псевдокод, реализующий такой выбор. Учитывая список весов, он возвращает случайный индекс (начиная с 0), выбранный с вероятностью, пропорциональной его весу. См. Также « Взвешенный выбор ».
METHOD WChoose(weights, value)
// Choose the index according to the given value
lastItem = size(weights) - 1
runningValue = 0
for i in 0...size(weights) - 1
if weights[i] > 0
newValue = runningValue + weights[i]
lastItem = i
// NOTE: Includes start, excludes end
if value < newValue: break
runningValue = newValue
end
end
// If we didn't break above, this is a last
// resort (might happen because rounding
// error happened somehow)
return lastItem
END METHOD
METHOD WeightedChoice(weights)
return WChoose(weights, RNDINTEXC(Sum(weights)))
END METHOD
Этот алгоритм представляет собой простой способ реализовать взвешенный выбор, но если он слишком медленный для вас, следующие альтернативы могут быть быстрее: