例如,如果您的概率非常适合百分比等,您可以采取一些技巧。
例如,如果您对百分比没问题,以下将起作用(以高内存开销为代价):
但是使用任意浮点概率的“真正”方法是在构建累积分布之后对其进行采样。这相当于将单位区间[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
但是,如果您没有解决问题……这实际上可能是最快的方法。=)