加权版本随机选择

2024-05-17 08:46:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要写一个random.choice的加权版本(列表中的每个元素被选中的概率都不同)。这就是我想到的:

def weightedChoice(choices):
    """Like random.choice, but each element can have a different chance of
    being selected.

    choices can be any iterable containing iterables with two items each.
    Technically, they can have more than two items, the rest will just be
    ignored.  The first item is the thing being chosen, the second item is
    its weight.  The weights can be any numeric values, what matters is the
    relative differences between them.
    """
    space = {}
    current = 0
    for choice, weight in choices:
        if weight > 0:
            space[current] = choice
            current += weight
    rand = random.uniform(0, current)
    for key in sorted(space.keys() + [current]):
        if rand < key:
            return choice
        choice = space[key]
    return None

这个功能在我看来过于复杂,而且很难看。我希望在座的每一个人都能提出一些改进的建议或者其他的方法。对我来说,效率并不像代码的整洁性和可读性那么重要。


Tags: thekeyishaveanyspacerandombe
3条回答
def weighted_choice(choices):
   total = sum(w for c, w in choices)
   r = random.uniform(0, total)
   upto = 0
   for c, w in choices:
      if upto + w >= r:
         return c
      upto += w
   assert False, "Shouldn't get here"

自1.7.0版以来,NumPy有一个支持概率分布的^{}函数。

from numpy.random import choice
draw = choice(list_of_candidates, number_of_items_to_pick,
              p=probability_distribution)

注意probability_distribution是一个顺序与list_of_candidates相同的序列。您还可以使用关键字replace=False来更改行为,以便不替换绘制的项。

自Python 3.6以来,有一个来自^{}模块的方法^{}

Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.0.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import random

In [2]: random.choices(
...:     population=[['a','b'], ['b','a'], ['c','b']],
...:     weights=[0.2, 0.2, 0.6],
...:     k=10
...: )

Out[2]:
[['c', 'b'],
 ['c', 'b'],
 ['b', 'a'],
 ['c', 'b'],
 ['c', 'b'],
 ['b', 'a'],
 ['c', 'b'],
 ['b', 'a'],
 ['c', 'b'],
 ['c', 'b']]

注意,random.choices将根据docs进行采样,并替换为

Return a k sized list of elements chosen from the population with replacement.

如果需要在不替换的情况下采样,那么作为@ronan-paixão's brilliant answer状态,可以使用^{},其replace参数控制这种行为。

相关问题 更多 >