如果我在列表中有一组项目。我想根据另一个权重列表从该列表中进行选择。
例如,我的收藏品是['one', 'two', 'three']
,权重是[0.2, 0.3, 0.5]
,我希望这种方法可以在所有抽奖的大约一半中给我'三'。
最简单的方法是什么?
答案 0 :(得分:79)
自numpy版本1.7起,您可以使用numpy.random.choice()
:
elements = ['one', 'two', 'three']
weights = [0.2, 0.3, 0.5]
from numpy.random import choice
print(choice(elements, p=weights))
答案 1 :(得分:24)
从Python 3.6开始,您可以使用random.choices
进行加权随机选择(替换)。
随机。选择(人口,权重=无,*,cum_weights =无,k = 1 )
使用示例:
import random
random.choices(['one', 'two', 'three'], [0.2, 0.3, 0.5], k=10)
# ['three', 'two', 'three', 'three', 'three',
# 'three', 'three', 'two', 'two', 'one']
答案 2 :(得分:11)
此函数有两个参数:权重列表和包含可供选择对象的列表:
from numpy import cumsum
from numpy.random import rand
def weightedChoice(weights, objects):
"""Return a random item from objects, with the weighting defined by weights
(which must sum to 1)."""
cs = cumsum(weights) #An array of the weights, cumulatively summed.
idx = sum(cs < rand()) #Find the index of the first weight over a random value.
return objects[idx]
它不使用任何python循环。
答案 3 :(得分:4)
您可以使用multinomial distribution(来自numpy)来做你想做的事。 E.g。
elements = ['one', 'two', 'three']
weights = [0.2, 0.3, 0.5]
import numpy as np
indices = np.random.multinomial( 100, weights, 1)
#=> array([[20, 32, 48]]), YMMV
results = [] #A list of the original items, repeated the correct number of times.
for i, count in enumerate(indices[0]):
results.extend( [elements[i]]*count )
因此,第一个位置的元素出现了20次,第二个位置的元素出现了32次,第三个位置的元素出现了48次,大致相当于给出权重所期望的值。
如果你很难绕过多项分布,我发现documentation真有帮助。
答案 4 :(得分:3)
如果您不想使用numpy
,可以使用以下相同的方法:
from random import random
from itertools import takewhile
def accumulate(iterator):
"""Returns a cumulative sum of the elements.
accumulate([1, 2, 3, 4, 5]) --> 1 3 6 10 15"""
current = 0
for value in iterator:
current += value
yield current
def weightedChoice(weights, objects):
"""Return a random item from objects, with the weighting defined by weights
(which must sum to 1)."""
limit = random()
return objects[sum(takewhile(bool, (value < limit for value in accumulate(weights))))]
我们使用itertools.takewhile()
来避免在达到我们想要停止的点后检查值,否则,这与Mischa Obrecht's answer基本相同,只是没有numpy
。
答案 5 :(得分:3)
如何初始化列表以使您的选择与预期权重相匹配。 在这里,我列出了100个代表你所需“拉”百分比的值。
>>> import random
>>> elements = ['one', 'two', 'three']
>>> weights = [0.2, 0.3, 0.5]
>>>
>>> # get "sum" of result list of lists (flattens list)
>>> choices = sum([[element] * int(weight * 100)for element, weight in zip(elements, weights)], [])
>>> random.choice(choices)
three
这不是累积的,但看起来它可能就是你想要的东西。
答案 6 :(得分:1)
要构建Maus' answer,如果您想重复获取加权随机值,这很棒,如果您只需要一个值,则可以通过组合numpy.random.multinomial()
和{{3 }}:
from itertools import compress
from numpy.random import multinomial
def weightedChoice(weights, objects):
"""Return a random item from objects, with the weighting defined by weights
(which must sum to 1)."""
return next(compress(objects, multinomial(1, weights, 1)[0]))