(Python)算法根据比例/权重随机选择一个键

时间:2010-04-03 08:41:26

标签: python

我有点不知道如何找到一个干净的算法来执行以下操作:

假设我有一个词典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次?

6 个答案:

答案 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)

还应该看一下 this link

为k制作两个列表,例如xkyk

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]