在Python中用选择、抽样和选择来从一个列表中随机选择元素。

商业

Python标准库的随机模块中的函数choice()、sample()和choice()可以用来从一个列表、元组、字符串或其他序列对象中随机选择和检索元素(随机抽样)。

choice()得到一个单一元素,sample()和options()得到一个多元素的列表。 sample()是不可恢复的提取,没有重复,options()是可恢复的提取,有重复。

这里提供了以下信息。

  • 随机选择一个元素。: random.choice()
  • 随机选择多个元素(没有重复的)。: random.sample()
  • 随机选择多个元素(有重复的)。: random.choices()
  • 固定随机数种子

随机选择一个元素。: random.choice()

通过随机模块的函数choose(),从列表中随机选择一个元素,并可以被检索到。

import random

l = [0, 1, 2, 3, 4]

print(random.choice(l))
# 1

这同样适用于图元和字符串。在字符串的情况下,将选择单个字符。

print(random.choice(('xxx', 'yyy', 'zzz')))
# yyy

print(random.choice('abcde'))
# b

如果指定一个空的列表、元组或字符串作为参数,则出错。

# print(random.choice([]))
# IndexError: Cannot choose from an empty sequence

随机选择多个元素(没有重复的)。: random.sample()

通过随机模块的函数sample(),你可以从一个列表中随机获得多个元素。不存在元素的重复(不可恢复的提取)。

第一个参数是一个列表,第二个参数是要检索的元素的数量。列表将被返回。

import random

l = [0, 1, 2, 3, 4]

print(random.sample(l, 3))
# [2, 4, 0]

print(type(random.sample(l, 3)))
# <class 'list'>

如果第二个参数设置为1,也会返回一个有一个元素的列表;如果设置为0,则列表为空。如果第二个参数是1,则返回一个有一个元素的列表;如果是0,则返回一个空列表;如果第一个参数多于列表中的元素数,则发生错误。

print(random.sample(l, 1))
# [3]

print(random.sample(l, 0))
# []

# print(random.sample(l, 10))
# ValueError: Sample larger than population or is negative

如果第一个参数是一个元组或一个字符串,返回的仍然是一个列表。

print(random.sample(('xxx', 'yyy', 'zzz'), 2))
# ['xxx', 'yyy']

print(random.sample('abcde', 2))
# ['b', 'e']

如果你想返回到一个元组或字符串,请使用tuple(),join()。

print(tuple(random.sample(('xxx', 'yyy', 'zzz'), 2)))
# ('xxx', 'yyy')

print(''.join(random.sample('abcde', 2)))
# dc

需要注意的是,价值是不被判断的,所以如果原始列表或元组包含有相同价值的元素,有可能会选择相同的价值。

l_dup = [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3]

print(random.sample(l_dup, 3))
# [3, 1, 1]

如果你想避免重复的值,你可以使用set()将其转换为一个集合(集合类型),只提取唯一的元素,然后使用sample()。

print(set(l_dup))
# {0, 1, 2, 3}

print(random.sample(set(l_dup), 3))
# [1, 3, 2]

随机选择多个元素(有重复的)。: random.choices()

随机模块的函数choice()允许你从一个列表中随机检索多个元素,与sample()不同,它允许选择重复的元素。

choices() 是Python 3.6中增加的一个函数。它在早期版本中是不可用的。

参数k指定要检索的元素的数量。重复是允许的,所以要检索的元素数可以大于原始列表中的元素数。

由于k是一个只有关键字的参数,因此有必要指定一个关键字,如k=3。

import random

l = [0, 1, 2, 3, 4]

print(random.choices(l, k=3))
# [2, 1, 0]

print(random.choices(l, k=10))
# [3, 4, 1, 4, 4, 2, 0, 4, 2, 0]

k的默认值是1;如果省略它,将返回一个有1个元素的列表。

print(random.choices(l))
# [1]

参数weights可以用来指定每个元素被选中的权重(概率),列表中元素的类型可以是int或float。

print(random.choices(l, k=3, weights=[1, 1, 1, 10, 1]))
# [0, 2, 3]

print(random.choices(l, k=3, weights=[1, 1, 0, 0, 0]))
# [0, 1, 1]

参数cum_weights也可以被指定为累积权重。以下示例代码中的cum_weights等同于上面的第一个权重。

print(random.choices(l, k=3, cum_weights=[1, 2, 3, 13, 14]))
# [3, 2, 3]

参数weights和cum_weights的默认值都是None,这意味着每个元素都以相同的概率被选中。

如果参数weights或cum_weights的长度(元素数)与原始列表不同,会发生错误。

# print(random.choices(l, k=3, weights=[1, 1, 1, 10, 1, 1, 1]))
# ValueError: The number of weights does not match the population_

同时指定weights和cum_weights也是一个错误。

# print(random.choices(l, k=3, weights=[1, 1, 1, 10, 1], cum_weights=[1, 2, 3, 13, 14]))
# TypeError: Cannot specify both weights and cumulative weights

在迄今为止的示例代码中,我们已经指定了一个列表作为第一个参数,但同样适用于图元和字符串。

固定随机数种子

通过给随机模块的函数seed()提供一个任意的整数,可以固定随机数种子并初始化随机数发生器。

在用相同的种子进行初始化后,元素总是以相同的方式被选择。

random.seed(0)
print(random.choice(l))
# 3

random.seed(0)
print(random.choice(l))
# 3