我有点不知道如何找到一个干净的算法来执行以下操作:
假设我有一个词典k:
>>> k = {'A': 68, 'B': 62, 'C': 47, 'D': 16, 'E': 81}
我现在想要根据它们在总(即总和)数量上的“权重”随机选择其中一个键。
>>> sum(k.values())
>>> 274
所以有一个
>>> 68.0/274.0
>>> 0.24817518248175183
24.81%的百分比改变了A的选择。
你会如何编写一个能够解决这个问题的算法?换句话说,这确保在10.000随机选择中,A将被选择2.481次?
答案 0 :(得分:10)
这是一个加权选择函数,有一些代码可以运用它。
import random
def WeightedPick(d):
r = random.uniform(0, sum(d.itervalues()))
s = 0.0
for k, w in d.iteritems():
s += w
if r < s: return k
return k
def Test():
k = {'A': 68, 'B': 62, 'C': 47, 'D': 16, 'E': 81}
results = {}
for x in xrange(10000):
p = WeightedPick(k)
results[p] = results.get(p, 0) + 1
print results
Test()
答案 1 :(得分:9)
这应该可以解决问题:
>>> k = {'A': 68, 'B': 62, 'C': 47, 'D': 16, 'E': 81}
>>> import random
>>> def weighted_pick(dic):
... total = sum(dic.itervalues())
... pick = random.randint(0, total-1)
... tmp = 0
... for key, weight in dic.iteritems():
... tmp += weight
... if pick < tmp:
... return key
答案 2 :(得分:2)
算法就是这个..
在1到274之间随机选择一个数字。为此,调用rand()函数(假设它返回0到1之间的值),将rand()乘以274.结果值现在应该在一个范围内。如果介于1和68之间,请选择A,如果介于69和130之间,则选择B,依此类推。这样,您的概率就会保持活跃,并且您的操作也会成功。
PS:我是一个Java人,不知道Python的语法。答案 3 :(得分:2)
当权重是相对较小的整数时(例如在您的示例中),最简单的方法是构建一个包含适当权重中所有字符的长字符串,并从中随机选择一个字符:
import random
d = {'A': 68, 'B': 62, 'C': 47, 'D': 16, 'E': 81}
s = ''.join(k*v for k,v in d.items())
random.choice(s)
请注意,如果权重较大,此方法会占用大量内存,在这种情况下,您可能更喜欢不同的解决方案。
答案 4 :(得分:2)
为k制作两个列表,例如xk
和yk
from scipy import stats
custm = stats.rv_discrete(name='test', values=(xk, yk))
custm.rvs(size=1)
答案 5 :(得分:-1)
几年前我开发了一个算法,在Perl和SQL中应用,您可以阅读它here,完成分析并测试它(最有可能)的正确性。
概念很简单:对于每个项目,选择一个随机数,通过一些取决于项目权重的函数,并选择具有最低值的项目。
该功能是:
x[i] = -log(1 - rand())/weight[i]