random ---生成伪随机数

源代码: Lib/random.py


该模块实现了各种分布的伪随机数生成器。

对于整数,有一个范围的统一选择。对于序列,有一个随机元素的统一选择,一个生成列表随机排列的函数,以及一个不替换的随机抽样函数。

在实线上,有计算均匀、正态(高斯)、对数正态、负指数、伽玛和贝塔分布的函数。对于生成角度分布,可以使用von mises分布。

几乎所有模块功能都依赖于基本功能 random() 在半开范围内均匀地产生一个随机浮点数[0.0,1.0]。python使用mersenne twister作为核心生成器。它产生53位精度浮点数,周期为2 * * 1993年1月1日。C中的底层实现既快速又线程安全。梅森捻线机是目前最广泛测试的随机数发生器之一。但是,由于它是完全确定性的,因此不适用于所有目的,也完全不适用于加密目的。

此模块提供的函数实际上是 random.Random 类。您可以实例化自己的 Random 获取不共享状态的生成器。

等级 Random 如果您想使用自己设计的不同的基本生成器,也可以被子类化:在这种情况下,重写 random()seed()getstate()setstate() 方法。或者,新的生成器可以提供 getrandbits() 方法---这允许 randrange() 在任意大范围内产生选择。

这个 random 模块还提供 SystemRandom 使用系统函数的类 os.urandom() 从操作系统提供的源代码生成随机数。

警告

此模块的伪随机生成器不应用于安全目的。有关安全或加密用途,请参阅 secrets 模块。

参见

松本和西村,“Mersenne Twister:A 623维均布均匀伪随机数发生器”,《ACM建模与计算机模拟学报》第8卷第1期,1998年1月,第3-30页。

Complementary-Multiply-with-Carry recipe 对于一个兼容的备用随机数生成器具有较长的周期和相对简单的更新操作。

记账功能

random.seed(a=None, version=2)

初始化随机数生成器。

如果 a 被省略或 None ,使用当前系统时间。如果操作系统提供随机性源,则使用它们而不是系统时间(请参见 os.urandom() 有关可用性的详细信息。

如果 a 是int,直接使用。

对于版本2(默认),a strbytesbytearray 对象转换为 int 所有的位都被使用了。

对于版本1(用于从旧版本的python中复制随机序列),用于 strbytes 产生更窄范围的种子。

在 3.2 版更改: 移到使用字符串种子中所有位的版本2方案。

3.9 版后已移除: 在未来 seed 必须是以下类型之一: NoneTypeintfloatstrbytesbytearray .

random.getstate()

返回捕获生成器当前内部状态的对象。此对象可以传递给 setstate() 恢复状态。

random.setstate(state)

state 应该从上一个调用获得 getstate()setstate() 将生成器的内部状态恢复为当时的状态 getstate() 被叫来。

字节函数

random.randbytes(n)

生成 n 随机字节。

此方法不应用于生成安全令牌。使用 secrets.token_bytes() 相反。

3.9 新版功能.

整数函数

random.randrange(stop)
random.randrange(start, stop[, step])

返回从中随机选择的元素 range(start, stop, step) . 这相当于 choice(range(start, stop, step)) ,但实际上不构建范围对象。

位置参数模式与 range() . 不应使用关键字参数,因为函数可能以意外的方式使用它们。

在 3.2 版更改: randrange() 在生成均匀分布的值方面更为复杂。以前它的风格是 int(random()*n) 可能会产生轻微的不均匀分布。

3.10 版后已移除: 不建议使用自动将非整数类型转换为等效整数。目前 randrange(10.0) 无损地转换为 randrange(10) 。在未来,这将引发一个 TypeError

3.10 版后已移除: 对于非整数值引发的异常,例如 randrange(10.5)randrange('10') 将从 ValueErrorTypeError

random.randint(a, b)

返回随机整数 N 这样的话 a <= N <= b . Alias randrange(a, b+1) .

random.getrandbits(k)

返回包含的非负Python整数 k 随机比特。此方法随MersenneTwister生成器一起提供,其他一些生成器也可能将其作为API的可选部分提供。当可用时, getrandbits() 启用 randrange() 来处理任意大的范围。

在 3.9 版更改: 此方法现在接受0 k .

序列函数

random.choice(seq)

从非空序列返回随机元素 seq .如果 seq 是空的,引发 IndexError .

random.choices(population, weights=None, *, cum_weights=None, k=1)

返回A k 从中选择的元素的大小列表 人口 替换。如果 人口 是空的,引发 IndexError .

如果A 砝码 指定序列,根据相对权重进行选择。或者,如果 cum_weights 给定序列,根据累计权重进行选择(可能使用 itertools.accumulate() )例如,相对权重 [10, 5, 30, 5] 等于累计权重 [10, 15, 45, 50] . 在内部,相对权重在进行选择之前转换为累积权重,因此提供累积权重可以节省工作。

如果既不 砝码 也不 cum_weights 如果指定,则选择的概率相等。如果提供了权重序列,则其长度必须与 人口 序列。这是一个 TypeError 同时指定两者 砝码cum_weights .

这个 砝码cum_weights 可以使用与 float 返回的值 random() (包括整数、浮点和分数,但不包括小数)。假设权重是非负的和有限的。A ValueError 如果所有权重都为零,则会提升。

对于给定的种子, choices() 具有相等权重的函数通常产生与重复调用不同的序列 choice() .使用的算法 choices() 使用浮点运算实现内部一致性和速度。使用的算法 choice() 默认为整数算法,并重复选择以避免舍入错误带来的小偏差。

3.6 新版功能.

在 3.9 版更改: 提出一个 ValueError 如果所有权重都为零。

random.shuffle(x[, random])

无序播放序列 x 就位。

可选参数 随机的 是返回[0.0,1.0]中的随机浮点的0参数函数;默认情况下,这是函数 random() .

要随机播放不可变序列并返回新的随机播放列表,请使用 sample(x, k=len(x)) 相反。

注意,即使是小的 len(x) ,的排列总数 x 可以比大多数随机数生成器的周期快速增长。这意味着一个长序列的大多数排列永远不会产生。例如,长度为2080的序列是最大的,可以在Mersenne捻线机随机数生成器的周期内匹配。

Deprecated since version 3.9, will be removed in version 3.11: 可选参数 随机的 .

random.sample(population, k, *, counts=None)

返回A k 从填充序列或集合中选择的唯一元素的长度列表。用于不更换的随机取样。

返回一个新列表,其中包含填充中的元素,同时保持原始填充不变。结果列表按选择顺序排列,这样所有子片也将是有效的随机样本。这使得抽奖优胜者(样本)可以分为特等奖和第二名优胜者(子执照)。

人口不必是 hashable 或独一无二。如果填充包含重复,则每次出现都是示例中的一个可能选择。

重复的元素可以一次指定一个,也可以仅使用可选关键字指定 计数 参数。例如, sample(['red', 'blue'], counts=[4, 2], k=5) 等于 sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5) .

要从整数范围中选择样本,请使用 range() 对象作为参数。这对于从大量人口中取样来说尤其快速和节省空间: sample(range(10000000), k=60) .

如果样本大小大于总体大小,则 ValueError 提高了。

在 3.9 版更改: 增加了 计数 参数。

3.9 版后已移除: 在未来 人口 必须是一个序列。实例 set 不再支持。必须首先将集合转换为 listtuple ,优选地以确定的顺序使样品可再现。

实值分配

以下函数生成特定的实值分布。函数参数是根据分布方程中的相应变量命名的,这在普通数学实践中是常用的;这些方程中的大多数都可以在任何统计文本中找到。

random.random()

返回范围[0.0,1.0]中的下一个随机浮点数。

random.uniform(a, b)

返回随机浮点数 N 这样的话 a <= N <= b 对于 a <= bb <= N <= a 对于 b < a .

终点值 b 根据公式中的浮点舍入,可以包含在范围内,也可以不包含在范围内。 a + (b-a) * random() .

random.triangular(low, high, mode)

返回随机浮点数 N 这样的话 low <= N <= high 和指定的 mode 在这些界限之间。这个 lowhigh 边界默认为零和一。这个 mode 参数默认为边界之间的中点,给出对称分布。

random.betavariate(alpha, beta)

β分布。参数的条件是 alpha > 0beta > 0 . 返回值的范围介于0和1之间。

random.expovariate(lambd)

指数分布。 兰伯德 是1.0除以期望的平均值。它应该是非零的。(参数将被称为“lambda”,但这是python中的保留字。)如果 兰伯德 是正的,如果 兰伯德 是否定的。

random.gammavariate(alpha, beta)

伽马分布。( Not 伽玛函数!)参数的条件是 alpha > 0beta > 0 .

概率分布函数为:

          x ** (alpha - 1) * math.exp(-x / beta)
pdf(x) =  --------------------------------------
            math.gamma(alpha) * beta ** alpha
random.gauss(mu, sigma)

高斯分布。 mu 是中庸,而且 西格玛 是标准偏差。这比 normalvariate() 函数定义如下。

多线程注意:当两个线程同时调用此函数时,它们可能会收到相同的返回值。这可以通过三种方式避免。1)让每个线程使用随机数生成器的不同实例。2)所有调用都加锁。3)使用速度较慢但线程安全的 normalvariate() 取而代之的是函数。

random.lognormvariate(mu, sigma)

对数正态分布。如果你取这个分布的自然对数,你会得到一个平均数的正态分布。 mu 和标准偏差 西格玛 . mu 可以有任何价值,并且 西格玛 必须大于零。

random.normalvariate(mu, sigma)

正态分布。 mu 是中庸,而且 西格玛 是标准偏差。

random.vonmisesvariate(mu, kappa)

mu 是平均角,以0到2之间的弧度表示 * pi卡帕 浓度参数,必须大于或等于零。如果 卡帕 等于零,此分布在0到2范围内减小为均匀随机角 * pi .

random.paretovariate(alpha)

帕累托分布。 阿尔法 是形状参数。

random.weibullvariate(alpha, beta)

威布尔分布。 阿尔法 是比例参数和 beta 是形状参数。

备用生成器

class random.Random([seed])

类,该类实现 random 模块使用的默认伪随机数生成器。

3.9 版后已移除: 在未来 seed 必须是以下类型之一: NoneTypeintfloatstrbytesbytearray .

class random.SystemRandom([seed])

使用的类 os.urandom() 从操作系统提供的源代码生成随机数的函数。并非所有系统都可用。不依赖软件状态,序列不可复制。因此, seed() 方法无效,将被忽略。这个 getstate()setstate() 方法提高 NotImplementedError 如果被召唤。

再现性说明

有时,能够再现由伪随机数生成器给出的序列是有用的。通过重新使用种子值,只要多个线程没有运行,相同的序列就应该可以从一个运行到另一个运行。

大多数随机模块的算法和种子设定函数在不同的python版本中都会发生变化,但有两个方面保证不会发生变化:

  • 如果添加了新的播种方法,那么将提供向后兼容的播种机。

  • 生成器的 random() 当兼容的播种机获得相同的种子时,方法将继续生成相同的序列。

示例

基本示例:

>>> random()                             # Random float:  0.0 <= x < 1.0
0.37444887175646646

>>> uniform(2.5, 10.0)                   # Random float:  2.5 <= x < 10.0
3.1800146073117523

>>> expovariate(1 / 5)                   # Interval between arrivals averaging 5 seconds
5.148957571865031

>>> randrange(10)                        # Integer from 0 to 9 inclusive
7

>>> randrange(0, 101, 2)                 # Even integer from 0 to 100 inclusive
26

>>> choice(['win', 'lose', 'draw'])      # Single random element from a sequence
'draw'

>>> deck = 'ace two three four'.split()
>>> shuffle(deck)                        # Shuffle a list
>>> deck
['four', 'two', 'ace', 'three']

>>> sample([10, 20, 30, 40, 50], k=4)    # Four samples without replacement
[40, 10, 50, 30]

模拟:

>>> # Six roulette wheel spins (weighted sampling with replacement)
>>> choices(['red', 'black', 'green'], [18, 18, 2], k=6)
['red', 'green', 'black', 'black', 'red', 'black']

>>> # Deal 20 cards without replacement from a deck
>>> # of 52 playing cards, and determine the proportion of cards
>>> # with a ten-value:  ten, jack, queen, or king.
>>> dealt = sample(['tens', 'low cards'], counts=[16, 36], k=20)
>>> dealt.count('tens') / 20
0.15

>>> # Estimate the probability of getting 5 or more heads from 7 spins
>>> # of a biased coin that settles on heads 60% of the time.
>>> def trial():
...     return choices('HT', cum_weights=(0.60, 1.00), k=7).count('H') >= 5
...
>>> sum(trial() for i in range(10_000)) / 10_000
0.4169

>>> # Probability of the median of 5 samples being in middle two quartiles
>>> def trial():
...     return 2_500 <= sorted(choices(range(10_000), k=5))[2] < 7_500
...
>>> sum(trial() for i in range(10_000)) / 10_000
0.7958

实例 statistical bootstrapping 使用带替换的重采样估计样本平均值的置信区间:

# http://statistics.about.com/od/Applications/a/Example-Of-Bootstrapping.htm
from statistics import fmean as mean
from random import choices

data = [41, 50, 29, 37, 81, 30, 73, 63, 20, 35, 68, 22, 60, 31, 95]
means = sorted(mean(choices(data, k=len(data))) for i in range(100))
print(f'The sample mean of {mean(data):.1f} has a 90% confidence '
      f'interval from {means[5]:.1f} to {means[94]:.1f}')

A的例子 resampling permutation test 确定统计显著性或 p-value 药物与安慰剂疗效的观察差异:

# Example from "Statistics is Easy" by Dennis Shasha and Manda Wilson
from statistics import fmean as mean
from random import shuffle

drug = [54, 73, 53, 70, 73, 68, 52, 65, 65]
placebo = [54, 51, 58, 44, 55, 52, 42, 47, 58, 46]
observed_diff = mean(drug) - mean(placebo)

n = 10_000
count = 0
combined = drug + placebo
for i in range(n):
    shuffle(combined)
    new_diff = mean(combined[:len(drug)]) - mean(combined[len(drug):])
    count += (new_diff >= observed_diff)

print(f'{n} label reshufflings produced only {count} instances with a difference')
print(f'at least as extreme as the observed difference of {observed_diff:.1f}.')
print(f'The one-sided p-value of {count / n:.4f} leads us to reject the null')
print(f'hypothesis that there is no difference between the drug and the placebo.')

模拟多服务器队列的到达时间和服务传递:

from heapq import heappush, heappop
from random import expovariate, gauss
from statistics import mean, quantiles

average_arrival_interval = 5.6
average_service_time = 15.0
stdev_service_time = 3.5
num_servers = 3

waits = []
arrival_time = 0.0
servers = [0.0] * num_servers  # time when each server becomes available
for i in range(100_000):
    arrival_time += expovariate(1.0 / average_arrival_interval)
    next_server_available = heappop(servers)
    wait = max(0.0, next_server_available - arrival_time)
    waits.append(wait)
    service_duration = gauss(average_service_time, stdev_service_time)
    service_completed = arrival_time + wait + service_duration
    heappush(servers, service_completed)

print(f'Mean wait: {mean(waits):.1f}   Max wait: {max(waits):.1f}')
print('Quartiles:', [round(q, 1) for q in quantiles(waits)])

参见

Statistics for Hackers 视频教程 Jake Vanderplas 关于统计分析,只使用几个基本概念,包括模拟、抽样、洗牌和交叉验证。

Economics Simulation 市场模拟 Peter Norvig 这表明了该模块提供的许多工具和分布的有效使用(高斯、均匀、样本、β变量、选择、三角形和RandRange)。

A Concrete Introduction to Probability (using Python) 教程 Peter Norvig 包括概率论的基础知识,如何编写模拟,以及如何使用Python执行数据分析。

食谱

默认设置 random() 返回范围内的2⁻⁵³的倍数 0.0 ≤ x < 1.0 。所有这些数字都是均匀分布的,并且完全可以表示为Python浮点数。然而,该区间中的许多其他可表示浮点不是可能的选择。例如, 0.05954861408025609 不是2⁻⁵³的整数倍。

下面的食谱采用了不同的方法。间隔中的所有浮点都是可能的选择。尾数来自范围内整数的均匀分布 2⁵² ≤ mantissa < 2⁵³ 。指数来自一个几何分布,其中的指数小于 -53 出现的频率是下一个较大指数的一半。

from random import Random
from math import ldexp

class FullRandom(Random):

    def random(self):
        mantissa = 0x10_0000_0000_0000 | self.getrandbits(52)
        exponent = -53
        x = 0
        while not x:
            x = self.getrandbits(32)
            exponent += x.bit_length() - 32
        return ldexp(mantissa, exponent)

real valued distributions 将使用新方法::

>>> fr = FullRandom()
>>> fr.random()
0.05954861408025609
>>> fr.expovariate(0.25)
8.87925541791544

该配方在概念上等同于从范围内的2⁻?⁰⁷⁴的所有倍数中选择的算法 0.0 ≤ x < 1.0 。所有这些数字都是均匀分布的,但大多数都必须向下舍入到最接近的可表示的Python浮点数。(值2⁻?⁰⁷⁴是最小的非正规化浮点数,等于 math.ulp(0.0) 。)

参见

Generating Pseudo-random Floating-Point Values 由Allen B.Downey撰写的一篇论文,描述了生成比通常生成的更多细粒度浮点的方法 random()