Есть хаки, которые вы можете сделать, если, например, ваши вероятности хорошо вписываются в проценты и т. Д.
Например, если у вас все в порядке с процентами, будет работать следующее (за счетвысокая нагрузка на память):
Но «реальный» способ сделать это с произвольными вероятностями с плавающей запятой - это произвести выборку из совокупного распределения после его построения.Это эквивалентно разделению единичного интервала [0,1] на 3 отрезка, обозначенных «a», «b» и «c»;затем выбираем случайную точку на единичном интервале и видим, какая ее отрезок отрезок.
#!/usr/bin/python3
def randomCategory(probDict):
"""
>>> dist = {'a':.1, 'b':.2, 'c':.3, 'd':.4}
>>> [randomCategory(dist) for _ in range(5)]
['c', 'c', 'a', 'd', 'c']
>>> Counter(randomCategory(dist) for _ in range(10**5))
Counter({'d': 40127, 'c': 29975, 'b': 19873, 'a': 10025})
"""
r = random.random() # range: [0,1)
total = 0 # range: [0,1]
for value,prob in probDict.items():
total += prob
if total>r:
return value
raise Exception('distribution not normalized: {probs}'.format(probs=probDict))
Нужно быть осторожным с методами, которые возвращают значения, даже если их вероятность равна 0.на всякий случай можно вставить if prob==0: continue
.
Для записи вот хакерский способ сделать это:
import random
def makeSampler(probDict):
"""
>>> sampler = makeSampler({'a':0.3, 'b':0.4, 'c':0.3})
>>> sampler.sample()
'a'
>>> sampler.sample()
'c'
"""
oneHundredElements = sum(([val]*(prob*100) for val,prob in probDict.items()), [])
def sampler():
return random.choice(oneHundredElements)
return sampler
Однако, если у вас нет проблем с разрешением... это на самом деле, вероятно, самый быстрый путь.=)