Веса определяют функцию распределения вероятности (pdf). Случайные числа из любого такого PDF могут быть получены путем applying its associated inverse cumulative distribution function единым случайных чисел между 0 и 1.
Смотрите также SO explanation этого, или, как объясняется Wikipedia:
If Y has a U[0,1] distribution then F⁻¹(Y) is distributed as F. This is used in random number generation using the inverse transform sampling-method.
import random
import bisect
import collections
def cdf(weights):
total = sum(weights)
result = []
cumsum = 0
for w in weights:
cumsum += w
result.append(cumsum/total)
return result
def choice(population, weights):
assert len(population) == len(weights)
cdf_vals = cdf(weights)
x = random.random()
idx = bisect.bisect(cdf_vals, x)
return population[idx]
weights=[0.3, 0.4, 0.3]
population = 'ABC'
counts = collections.defaultdict(int)
for i in range(10000):
counts[choice(population, weights)] += 1
print(counts)
# % test.py
# defaultdict(<type 'int'>, {'A': 3066, 'C': 2964, 'B': 3970})
enter code here
The choice
функции выше использует bisect.bisect
, поэтому выбор взвешенной случайной величины производится в O(log n)
, где n
- это длина weights
.
Обратите внимание, что в версии 1.7.0, NumPy имеет Cythonized np.random.choice function. Например, это порождает 1000 выборок из популяции [0,1,2,3]
[0.1, 0.2, 0.3, 0.4]
с весами:
import numpy as np
np.random.choice(4, 1000, p=[0.1, 0.2, 0.3, 0.4])
np.random.choice
также имеет параметр replace
для отбора проб с или без замены.
Теоретически лучше алгоритм является Alias Method. Он создает таблицу, которая требует времени O(n)
, но после этого образцы могут быть нарисованы в O(1)
времени. Итак, если вам нужно нарисовать много образцов, теоретически метод псевдонимов может быть быстрее. Существует реализация Python метода псевдонима Walker here и numpy version here.
Поиск найдено несколько похожих/идентичных вопросов [здесь] (http://stackoverflow.com/questions/526255/probability-distribution-in-python) и [здесь] (http://stackoverflow.com/questions/1056151/random-python-dictionary-key-weighted-by-values) – snapshoe
@ ma3: Одна из слабых сторон этого сайта заключается в том, что, поскольку старые вопросы, как правило, игнорируются, нет механизма или мотивации для улучшения их. Я думаю, что мой ответ значительно лучше, чем, по крайней мере, более высокие ответы на эти вопросы - не читал нижних, но никто никогда не увидит его, если я разместил его на них. –