加权选择简短

Mis*_*cht 46 python numpy

如果我在列表中有一组项目.我想根据另一个权重列表从该列表中进行选择.

例如我的收藏是['one', 'two', 'three']和权重[0.2, 0.3, 0.5],我希望这个方法在所有抽奖的大约一半中给我'三'.

最简单的方法是什么?

Qua*_*lis 83

版本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))
Run Code Online (Sandbox Code Playgroud)

  • 这个答案应该得到验证. (4认同)
  • 完美的解决方案`l = [选择(元素,p =权重)_在范围(1000)]和`来自集合导入计数器; 计数器(l)`传递:`计数器({'三':498,'二':281,'一':221})`. (2认同)

Est*_*eis 34

从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']
Run Code Online (Sandbox Code Playgroud)


Mis*_*cht 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]
Run Code Online (Sandbox Code Playgroud)

它不使用任何python循环.

  • 这些评论似乎具有误导性.`cumsum()`给出累积值,而不是布尔值.要清楚,这确实有效,但评论与实际发生的情况不符. (2认同)

Mau*_*aus 5

您可以使用多项分布(来自 numpy)来做您想做的事。例如

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 )
Run Code Online (Sandbox Code Playgroud)

所以第一个位置的元素出现了 20 次,第二个位置的元素出现了 32 次,第三个位置的元素出现了 48 次,这大致是给定权重的预期。

如果您很难理解多项式分布,我发现文档真的很有帮助。

  • 请注意,您可以将结果构建减少到`itertools.chain.from_iterable([elements[i]]*count, for i, count in enumerate(indices[0]))`,这样会更快。 (2认同)