以百分比为基础从列表中选择项目

时间:2014-10-16 17:01:10

标签: python

我正在尝试使用Python创建一个程序,该程序从列表中获取名称,并以随机顺序显示列表中的名称,同时仅使用每个名称一次。我已经做到了这一点,并使用以下代码:

import random

drivers = [
"John Doe",
"Bill Smith",
"Trent Baxter",
"Ray Olson",
]

random.shuffle(drivers)

for position in drivers:
    print(position)

OUPUT:

Bill Smith
John Doe
Ray Olson
Trent Baxter

这样可行,但是我想让程序为每个名称指定值以使它们更多,或者更不可能被选中,同时仍然只选择一次名称。

3 个答案:

答案 0 :(得分:0)

这是一个简单的变体,可以做你想要的。请注意,几乎可以肯定很多更有效的方法,因为它在运行时当前 O(n ^ 2)并使用 n * m < / strong>最大内存,其中 n 是输入填充大小, m 是平均权重,因为它构建的列表具有每个权重的输入列表值的一个副本。

import random
import itertools

def random_weighted_shuffle(input_population):
    '''
    :param input_population: {name:weight}, where weight is the 'number of chances' that this particular name will be drawn
    '''
    out_list = []
    while input_population:
        lotto_list = list(itertools.chain.from_iterable([name]*weight for name, weight in input_population.iteritems()))
        selection  = lotto_list[random.randint(0,len(lotto_list)-1)]
        del input_population[selection]
        out_list.append(selection)
    return out_list

非常重要说明:如上所述,此方法对输入字典具有破坏性。

用法:

>>> random_weighted_shuffle({'a':10,'b':2,'c':5})
['a', 'b', 'c']
>>> random_weighted_shuffle({'a':10,'b':2,'c':5})
['a', 'c', 'b']
>>> random_weighted_shuffle({'a':10,'b':2,'c':5})
['b', 'c', 'a']
>>> random_weighted_shuffle({'a':10,'b':2,'c':5})
['c', 'a', 'b']
>>> random_weighted_shuffle({'a':10,'b':2,'c':5})
['a', 'c', 'b']

答案 1 :(得分:0)

你的问题可以用不同的方式解释。如果你的意思是挑选元素的数量没有固定,那么每个元素都有自己被挑选的概率,并且所有选择都是独立发生的,而不是以这种方式解决任务(看起来像 O(n) )):

from scipy.stats import bernoulli

probs = [0.2, 0.5, 0.7, 0.1]

for i, d in enumerate(drivers):
    if bernoulli.rvs(probs[i], size=1)[0]:   # generates a list of length 1 containing Bernoulli random variable
        print d

答案 2 :(得分:0)

仅使用标准模块进行解答:

from itertools import accumulate
from random import uniform

class ProbItem(object):
    def __init__(self, value, prob):
        self.value = value
        self.prob = prob

def pick(items):
    accum = list(accumulate(item.prob for item in items))
    rand = uniform(0, accum[-1])
    for i, prob in enumerate(accum):
        if rand < prob:
            return items.pop(i).value

drivers = [
    ProbItem("John Doe", 23.7),
    ProbItem("Bill Smith", 17),
    ProbItem("Trent Baxter", 12.43),
    ProbItem("Ray Olson", 9.99),
]

while (drivers):
    print(pick(drivers))

根据您的需要,建造发电机会更好......