从具有相同概率的多个列表中选择随机值

时间:2017-04-27 02:26:28

标签: python

假设我有3个列表

old_people = ['George', 'Bob', 'Owen']
young_people = ['Sarah', 'Gwen', 'Brittney']
mid_age = ['Larry', 'Missy', 'Greg']


import random
random.choice(old_people)

从一个选择中,我如何以相同的概率从所有三个列表中选择1个名字?

5 个答案:

答案 0 :(得分:5)

假设所有三个名单中的" 1名称具有相同的概率"你的意思是每个名称都有相同的被选中概率,因为在python 3.6中引入了random.choices,它可以相对直接地做到这一点,而不需要连接来构建一个巨大的列表。例如:

In [52]: seqs = [old_people, young_people, mid_age]

In [53]: random.choice(random.choices(seqs, weights=map(len, seqs))[0])
Out[53]: 'Larry'

我们选择其中一个列表使用长度来加权我们的选择,然后我们从该列表中统一选择。 seqs只列出对子列表的引用,因此不会执行连接。

作为统一性的健全性检查:

In [65]: seqs = [["Bob"], ["Fred", "Sally"]]

In [66]: Counter(random.choice(random.choices(seqs, weights=map(len, seqs))[0]) 
                 for _ in range(10**6))
Out[66]: Counter({'Bob': 333484, 'Fred': 332755, 'Sally': 333761})

答案 1 :(得分:2)

如果您不想承担将多个列表连接在一起的开销,(在这种情况下,我不会责怪您 - 它应该是O的O(n)( 1)操作),你可以通过选择与连接列表中的位置相对应的索引,然后索引相应的列表来做同样的事情。在代码中:

import random

def choose(*lists):
    total_len = sum(map(len, lists))
    index = random.randint(0, total_len - 1)
    for l in lists:
        if index < len(l):
            return l[index]
        else:
            index = index - len(l)

这会计算一个索引,然后遍历列表列表,直到找到它所在的列表,然后返回相应的元素。

答案 2 :(得分:1)

另一种可能的实施方式。假设输入结构良好。

import random
def choose(*lists):
  return lists[random.randint(0, len(lists) - 1)] \
    [random.randint(0, len(lists[0]) - 1)]

<强>解释

这会从列表列表中随机选择一个列表:

lists[random.randint(0, len(lists) - 1)]

这将从随机选择的列表中随机选择一个项目:

[random.randint(0, len(lists[0]) - 1)]

答案 3 :(得分:0)

如果所有名称之间的概率必须相等:

random.choice(old_people + young_people + mid_age)

这里需要注意的是,如果一个列表中包含更多字符串,则“列表”具有更高的被选中概率。

如果概率需要使得3个列表应该具有相同的被拣选概率并且在该列表中,则每个字符串具有相等的概率,然后它变为如下:

pick1 = random.choice(old_people)
pick2 = random.choice(young_people)
pick3 = random.choice(mid_age)
foo = [pick1 ,pick2,pick3]
random.choice(foo)

答案 4 :(得分:0)

您可以使用Psidom的建议(除非列表非常大或者这是一个紧密的循环)或shashank的建议 - 取决于您对“等概率”的定义:

random.choice(old_people + young_people + mid_age)

#or

random.choice([random.choice(_) for _ in 
              (old_people + young_people + mid_age)])

第一个将创建一个连接3个列表的新列表,将其作为参数传递给random.choice并丢弃它,而第二个将从每个列表中选择一个随机元素然后再选择其中一个选项(如果您对“等概率”的定义符合这一要求,您可以在这里停止。

如果列表很小但你在循环中调用random.choice将重复一百万次,那么最好将连接列表存储在一个变量中:

choices = old_people + young_people + mid_age

while True:
    choice = random.choice(choices)
    do_something_with(choice)

如果列表真的很大,你可能想避免使用类似的东西(未经测试)在内存中创建一个新的大型大型列表:

def choice(*lists):
    lens = [len(_) for _ in lists]
    choice = random.randint(0, sum(lens) - 1)
    i = 0
    for j, size in enumerate(lens):
        i += size
        if choice < i:
           if j:
               return lists[j][choice - i]
           return lists[j][choice]

choice(old_people, young_people, mid_age)    

[编辑]

如果您有幸使用Python 3.6或更高版本,则按照DSM的建议进行操作:

choices = old_people, young_people, mid_age
choice = random.choice(random.choices(
    choices, 
    weights=[len(_) for _ in choices]
)[0])