【问题标题】:Python: Sample N random items from list with weights but without repetitionPython:从具有权重但不重复的列表中采样 N 个随机项目
【发布时间】:2020-09-22 17:08:08
【问题描述】:

我正在创建一种彩票系统,其中个人(通过唯一 ID 标识)可以拥有多张彩票进入彩票,但是一旦被选中,就无法再次中奖。

这是我的例子:

import random
entrants = ['John', 'Jane', 'Cthulhu']
allEntries = []
for entrant in entrants:
    numEntries = random.randint(1, 5)
    print("%s has %d entries" % (entrant, numEntries))
    allEntries.extend([entrant] * numEntries)
print(random.sample(allEntries, k=2))

我的想法是创建一个列表,其中包含 entrant 的名称 numEntries 次,然后从中进行选择。然而,有时同一个人被选为两个获胜者。有没有办法为每个参赛者设置权重?

我尝试将random.choices()weights 一起使用,但这也可以选择同一个人作为两个获胜者。

import random
weights = []
for entrant in entrants:
    numEntries = random.randint(1, 5)
    print("%s has %d entries" % (entrant, numEntries))
    weights.extend([numEntries])
print(random.choices(entrants, weights=weights, k=2))

【问题讨论】:

  • 为什么不随机打乱列表并从中获取 N 个项目?
  • @RandomDavis 它的权重如何?名单可以改组,但仍然有同一个人成为获胜者。
  • stackoverflow.com/questions/43549515/… 的可能重复项 - 尽管这主要针对 numpy 解决方案。
  • 您想选出多少名获奖者?它总是 2 还是也不同?
  • 不幸的是,由于您是从两个不同(但相关)的加权样本中提取的,randomnumpy.random 不支持您的用例的简单解决方案。一次选出一个获胜者,从您的数据集中删除每个获胜者。

标签: python random


【解决方案1】:

做你想做的最简单的方法是使用 NumPy。以下函数可以完成所有工作:

numpy.random.choice(a, size=None, replace=True, p=None)

a:您要从中选择的类数组对象(例如列表)

size: 要选择的元素数

replace:表示是否允许多次选择同一个项目-在你的情况下False

p: 类似数组的对象(例如列表),其中元素的概率(相同顺序)

参考:https://numpy.org/doc/stable/reference/random/generated/numpy.random.choice.html

【讨论】:

    【解决方案2】:

    一般的随机选择不重复的方法是打乱条目,取前N个。

    from random import shuffle
    
    N = 1
    entrants = ['John', 'Jane', 'Cthulhu']
    shuffle(entrants)
    print(entrants[:N])
    

    或者更直接

    from random import sample
    
    N = 1
    entrants = ['John', 'Jane', 'Cthulhu']
    print(sample(entrants, N))
    

    但是,您对加权抽样的要求意味着您需要的还不止这些。

    def unique_sample(population, count):
      shuffle(population)
      unique = set()
      it = iter(population)
      while len(unique) < count:
        elem = next(it)
        if elem not in unique:
          yield elem
        unique.add(elem)
    

    【讨论】:

    • 如果每个人都有 1 个条目但每个人的权重不同,则此方法有效。
    • @Bijan 如果权重是整数,那么你可以重复输入它的权重
    • 但是重复输入意味着您不能保证唯一的值。我想不出一个简单的原生 Python 解决方案。 (但是,当样本可以使用时,不要使用 shuffle!如果序列大小很大,这将是一个更昂贵的操作。)
    【解决方案3】:

    我喜欢将参赛者姓名乘以参赛作品数量的解决方案。我的解决方案的问题是,如果我选择了获胜者,他们仍然在池中。

    import random
    
    def selectWinners(allEntries, numWinners):
        winners = []
        print("Selecting %d winners" % numWinners)
        print("Entries", allEntries)
        for i in range(numWinners):
            winner = random.choice(allEntries)
            print("%d: %s won" % (i+1, winner))
            allEntries[:] = [x for x in allEntries if x != winner]
    
    entrants = ['John', 'Jane', 'Cthulhu']
    allEntries = []
    for entrant in entrants:
        numEntries = random.randint(1, 5)
        print("%s has %d entries" % (entrant, numEntries))
        allEntries.extend([entrant] * numEntries)
    selectWinners(allEntries, 2)
    

    返回如下输出:

    John has 1 entries
    Jane has 1 entries
    Cthulhu has 5 entries
    Selecting 2 winners
    Entries ['John', 'Jane', 'Cthulhu', 'Cthulhu', 'Cthulhu', 'Cthulhu', 'Cthulhu']
    1: Cthulhu won
    2: Jane won
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多