我们假设我们得到了如下列表:
list = [[A,10,3],[B,5,2],[C,8,1]]
对于列表中的每个项目,可以选择可以通过softmax计算的概率。例如,对于第一个元素(A),我们有:
from math import exp
A_probability = exp(list[0][2]/list[0][1] /
(exp(list[0][2]/list[0][1]) +
exp(list[1][2]/list[1][1]) +
exp(list[2][2]/list[2][1])))
如何根据每个项目的可能性随机选择列表中的项目?
答案 0 :(得分:3)
我假设您有一个预先计算的概率列表(比如probs
),列表中的每个索引(比如data
)都要选择。
此外,probs
和data
显然必须具有相同的长度,probs
的条目必须是非负数,总计为1
。
根据data
中被称为轮盘赌轮的分布,有一种简洁而简单的技术可以随机选择probs
中的索引。在Python中,我相信,它应该看起来像这样
import random
data = ['A', 'B', 'C', 'D']
probs = [0.2, 0.4, 0.3, 0.1]
def roulette_wheel(probs):
rand = random.random()
for slot, prob in enumerate(probs):
rand -= prob
if rand < 0.0:
return slot
请注意,这可以通过将1
乘以术语rand
推广到非负权重列表(不必加sum(weights)
)。我相信,我第一次在一本关于Pascal编程的书中看到了这个可爱的想法。
修改强>:
正如MadPhysicist在comment中所建议的那样,如果需要从同一数据中反复绘制,这可以提高效率。在这种情况下,可以预先计算累积分布函数,然后只对索引执行二进制搜索,使cumulative prob. <= rand ~ U(0, 1)
。在Python中,这可能看起来像以下
from random import random
from bisect import bisect_right
def cdf(probs):
cdf = []
total = 0.0
for p in probs:
total += p
cdf.append(total)
return cdf
def roulette_wheel_bisect(cdf):
return bisect_right(cdf, random())
# compute cdf
cumsum = cdf(probs)
# randomly draw 10 indexes
for i in range(0, 10):
print(roulette_wheel_bisect(cumsum))
免责声明:我不是一个交易的Python程序员,所以上面的代码应该只说明一般的想法。对于实际应用来说,它可能不是很强大。例如,如果可以,您应该始终使用经过良好测试的标准库numpy。
<强> EDIT2 强>:
我刚刚了解到numpy
有numpy.random.choice,它正是您所需要的。例如:
from numpy import random
data = ['A', 'B', 'C', 'D']
probs = [0.2, 0.4, 0.3, 0.1]
# randomly draw 10 list elements with replacement
for i in range(0, 10):
print(random.choice(data, p=probs))