按权重选择随机项

9 投票
5 回答
12883 浏览
提问于 2025-04-17 12:57

我有大约10000个项目的列表。现在的情况是,每个项目都有一个相关的权重(优先级或重要性)。目前最小的权重是-100(负数和零的值可以去掉),而最高的权重是1500。这个权重是由人们的直觉决定的(也就是他们觉得这个项目对社区有多重要)。因为确定哪个项目最重要并不容易,所以我想引入一些随机因素,这样权重较低的项目被选中的机会就会少一些,并且它们的权重在未来会进行调整(这是一种常识和随机性的结合)。

你知道怎么写一个叫getItem的函数吗?

def getItem(dict):
  # this function should return random item from 
  # the dictionary of item-weight pairs (or list of tuples)
  # Normally I would return only random item from the dictionary,
  # but now I'd like to have this: The item with weight 1500 should
  # have much more chance to be returned than the item with weight 10.
  # What's my idea is to sum up the weights of all items and then compute
  # some ratios. But maybe you have better idea.
  return randomItem

谢谢

5 个回答

3

你需要先随机抽取一个数字,这个数字的范围是从0到所有权重的总和(权重都是正数)。然后,你可以通过使用bisect这个工具,从一个列表中找到对应的项目。你可以在这里查看bisect的详细信息:http://docs.python.org/library/bisect.html(这是bisect的标准模块)。

import random 
import bisect
weight = {'a':0.3,'b':3.2,'c':2.4}
items = weight.keys()
mysum = 0
breakpoints = [] 
for i in items:
    mysum += weight[i]
    breakpoints.append(mysum)

def getitem(breakpoints,items):
    score = random.random() * breakpoints[-1]
    i = bisect.bisect(breakpoints, score)
    return items[i] 

print getitem(breakpoints,items)
10

Python 3.6 版本引入了一个新功能,叫做 random.choices()

def get_item(items, items_weights):
    return random.choices(items, weights=items_weights)[0]
14

看看这个,我觉得这正是你需要的,它对不同的方法做了一些很好的比较。你可以在这里找到关于Python中的加权随机生成的内容。

这里建议的最简单的方法是:

import random

def weighted_choice(weights):
    totals = []
    running_total = 0

    for w in weights:
        running_total += w
        totals.append(running_total)

    rnd = random.random() * running_total
    for i, total in enumerate(totals):
        if rnd < total:
            return i

你可以在上面的链接中找到更多细节和可能的改进,以及一些不同的方法。

撰写回答