random --- 生成偽隨機數(shù)?

源碼: Lib/random.py


該模塊實現(xiàn)了各種分布的偽隨機數(shù)生成器。

對于整數(shù),從范圍中有統(tǒng)一的選擇。 對于序列,存在隨機元素的統(tǒng)一選擇、用于生成列表的隨機排列的函數(shù)、以及用于隨機抽樣而無需替換的函數(shù)。

在實數(shù)軸上,有計算均勻、正態(tài)(高斯)、對數(shù)正態(tài)、負指數(shù)、伽馬和貝塔分布的函數(shù)。 為了生成角度分布,可以使用 von Mises 分布。

幾乎所有模塊函數(shù)都依賴于基本函數(shù) random() ,它在半開放區(qū)間 [0.0,1.0) 內(nèi)均勻生成隨機浮點數(shù)。 Python 使用 Mersenne Twister 作為核心生成器。 它產(chǎn)生 53 位精度浮點數(shù),周期為 2**19937-1 ,其在 C 中的底層實現(xiàn)既快又線程安全。 Mersenne Twister 是現(xiàn)存最廣泛測試的隨機數(shù)發(fā)生器之一。 但是,因為完全確定性,它不適用于所有目的,并且完全不適合加密目的。

這個模塊提供的函數(shù)實際上是 random.Random 類的隱藏實例的綁定方法。 你可以實例化自己的 Random 類實例以獲取不共享狀態(tài)的生成器。

如果你想使用自己設(shè)計的不同基礎(chǔ)生成器,類 Random 也可以作為子類:在這種情況下,重載 random() 、 seed()getstate() 以及 setstate() 方法。可選地,新生成器可以提供 getrandbits() 方法——這允許 randrange() 在任意大的范圍內(nèi)產(chǎn)生選擇。

random 模塊還提供 SystemRandom 類,它使用系統(tǒng)函數(shù) os.urandom() 從操作系統(tǒng)提供的源生成隨機數(shù)。

警告

不應(yīng)將此模塊的偽隨機生成器用于安全目的。 有關(guān)安全性或加密用途,請參閱 secrets 模塊。

參見

M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-dimensionally equidistributed uniform pseudorandom number generator", ACM Transactions on Modeling and Computer Simulation Vol. 8, No. 1, January pp.3--30 1998.

Complementary-Multiply-with-Carry recipe 用于兼容的替代隨機數(shù)發(fā)生器,具有長周期和相對簡單的更新操作。

簿記功能?

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

初始化隨機數(shù)生成器。

如果 a 被省略或為 None ,則使用當前系統(tǒng)時間。 如果操作系統(tǒng)提供隨機源,則使用它們而不是系統(tǒng)時間(有關(guān)可用性的詳細信息,請參閱 os.urandom() 函數(shù))。

如果 a 是 int 類型,則直接使用。

對于版本2(默認的),str 、 bytesbytearray 對象轉(zhuǎn)換為 int 并使用它的所有位。

對于版本1(用于從舊版本的Python再現(xiàn)隨機序列),用于 strbytes 的算法生成更窄的種子范圍。

在 3.2 版更改: 已移至版本2方案,該方案使用字符串種子中的所有位。

在 3.11 版更改: The seed must be one of the following types: NoneType, int, float, str, bytes, or bytearray.

random.getstate()?

返回捕獲生成器當前內(nèi)部狀態(tài)的對象。 這個對象可以傳遞給 setstate() 來恢復(fù)狀態(tài)。

random.setstate(state)?

state 應(yīng)該是從之前調(diào)用 getstate() 獲得的,并且 setstate() 將生成器的內(nèi)部狀態(tài)恢復(fù)到 getstate() 被調(diào)用時的狀態(tài)。

用于字節(jié)數(shù)據(jù)的函數(shù)?

random.randbytes(n)?

生成 n 個隨機字節(jié)。

此方法不可用于生成安全憑據(jù)。 那應(yīng)當使用 secrets.token_bytes()。

3.9 新版功能.

整數(shù)用函數(shù)?

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

Return a randomly selected element from range(start, stop, step).

This is roughly equivalent to choice(range(start, stop, step)) but supports arbitrarily large ranges and is optimized for common cases.

The positional argument pattern matches the range() function.

Keyword arguments should not be used because they can interpreted in unexpected ways. For example range(start=100) is interpreted as range(0, 100, 1).

在 3.2 版更改: randrange() 在生成均勻分布的值方面更為復(fù)雜。 以前它使用了像``int(random()*n)``這樣的形式,它可以產(chǎn)生稍微不均勻的分布。

在 3.12 版更改: Automatic conversion of non-integer types is no longer supported. Calls such as randrange(10.0) and randrange(Fraction(10, 1)) now raise a TypeError.

random.randint(a, b)?

返回隨機整數(shù) N 滿足 a <= N <= b。相當于 randrange(a, b+1)。

random.getrandbits(k)?

返回具有 k 個隨機比特位的非負 Python 整數(shù)。 此方法隨 MersenneTwister 生成器一起提供,其他一些生成器也可能將其作為 API 的可選部分提供。 在可能的情況下,getrandbits() 會啟用 randrange() 來處理任意大的區(qū)間。

在 3.9 版更改: 此方法現(xiàn)在接受零作為 k 的值。

序列用函數(shù)?

random.choice(seq)?

從非空序列 seq 返回一個隨機元素。 如果 seq 為空,則引發(fā) IndexError

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

population 中選擇替換,返回大小為 k 的元素列表。 如果 population 為空,則引發(fā) IndexError。

如果指定了 weight 序列,則根據(jù)相對權(quán)重進行選擇。 或者,如果給出 cum_weights 序列,則根據(jù)累積權(quán)重(可能使用 itertools.accumulate() 計算)進行選擇。 例如,相對權(quán)重``[10, 5, 30, 5]``相當于累積權(quán)重``[10, 15, 45, 50]``。 在內(nèi)部,相對權(quán)重在進行選擇之前會轉(zhuǎn)換為累積權(quán)重,因此提供累積權(quán)重可以節(jié)省工作量。

如果既未指定 weight 也未指定 cum_weights ,則以相等的概率進行選擇。 如果提供了權(quán)重序列,則它必須與 population 序列的長度相同。 一個 TypeError 指定了 weightscum_weights

weightscum_weights 可使用 random() 所返回的能與 float 值進行相互運算的任何數(shù)字類型(包括整數(shù)、浮點數(shù)、分數(shù)但不包括 decimal)。 權(quán)重值應(yīng)當非負且為有限的數(shù)值。 如果所有的權(quán)重值均為零則會引發(fā) ValueError

對于給定的種子,具有相等加權(quán)的 choices() 函數(shù)通常產(chǎn)生與重復(fù)調(diào)用 choice() 不同的序列。 choices() 使用的算法使用浮點運算來實現(xiàn)內(nèi)部一致性和速度。 choice() 使用的算法默認為重復(fù)選擇的整數(shù)運算,以避免因舍入誤差引起的小偏差。

3.6 新版功能.

在 3.9 版更改: 如果所有權(quán)重均為負值則將引發(fā) ValueError。

random.shuffle(x)?

就地將序列 x 隨機打亂位置。

要改變一個不可變的序列并返回一個新的打亂列表,請使用``sample(x, k=len(x))``。

請注意,即使對于小的 len(x)x 的排列總數(shù)也可以快速增長,大于大多數(shù)隨機數(shù)生成器的周期。 這意味著長序列的大多數(shù)排列永遠不會產(chǎn)生。 例如,長度為2080的序列是可以在 Mersenne Twister 隨機數(shù)生成器的周期內(nèi)擬合的最大序列。

Deprecated since version 3.9, removed in version 3.11: 可選形參 random。

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

Return a k length list of unique elements chosen from the population sequence. Used for random sampling without replacement.

返回包含來自總體的元素的新列表,同時保持原始總體不變。 結(jié)果列表按選擇順序排列,因此所有子切片也將是有效的隨機樣本。 這允許抽獎獲獎?wù)撸颖荆┍粍澐譃榇螵労偷诙@勝者(子切片)。

總體成員不必是 hashable 或 unique 。 如果總體包含重復(fù),則每次出現(xiàn)都是樣本中可能的選擇。

重復(fù)的元素可以一個個地直接列出,或使用可選的僅限關(guān)鍵字形參 counts 來指定。 例如,sample(['red', 'blue'], counts=[4, 2], k=5) 等價于 sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5)。

要從一系列整數(shù)中選擇樣本,請使用 range() 對象作為參數(shù)。 對于從大量人群中采樣,這種方法特別快速且節(jié)省空間:sample(range(10000000), k=60) 。

如果樣本大小大于總體大小,則引發(fā) ValueError 。

在 3.9 版更改: 增加了 counts 形參。

在 3.11 版更改: The population must be a sequence. Automatic conversion of sets to lists is no longer supported.

實值分布?

以下函數(shù)生成特定的實值分布。如常用數(shù)學實踐中所使用的那樣,函數(shù)形參以分布方程中的相應(yīng)變量命名,大多數(shù)這些方程都可以在任何統(tǒng)計學教材中找到。

random.random()?

返回 [0.0, 1.0) 范圍內(nèi)的下一個隨機浮點數(shù)。

random.uniform(a, b)?

返回一個隨機浮點數(shù) N ,當 a <= ba <= N <= b ,當 b < ab <= N <= a 。

取決于等式 a + (b-a) * random() 中的浮點舍入,終點 b 可以包括或不包括在該范圍內(nèi)。

random.triangular(low, high, mode)?

返回一個隨機浮點數(shù) N ,使得 low <= N <= high 并在這些邊界之間使用指定的 modelowhigh 邊界默認為零和一。 mode 參數(shù)默認為邊界之間的中點,給出對稱分布。

random.betavariate(alpha, beta)?

Beta 分布。 參數(shù)的條件是 alpha > 0beta > 0。 返回值的范圍介于 0 和 1 之間。

random.expovariate(lambd)?

指數(shù)分布。 lambd 是 1.0 除以所需的平均值,它應(yīng)該是非零的。 (該參數(shù)本應(yīng)命名為 “l(fā)ambda” ,但這是 Python 中的保留字。)如果 lambd 為正,則返回值的范圍為 0 到正無窮大;如果 lambd 為負,則返回值從負無窮大到 0。

random.gammavariate(alpha, beta)?

Gamma 分布。 ( 不是 gamma 函數(shù)! ) 參數(shù)的條件是 alpha > 0beta > 0。

概率分布函數(shù)是:

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

正態(tài)分布,也稱高斯分布。 mu 為平均值,而 sigma 為標準差。 此函數(shù)要稍快于下面所定義的 normalvariate() 函數(shù)。

多線程注意事項:當兩個線程同時調(diào)用此方法時,它們有可能將獲得相同的返回值。 這可以通過三種辦法來避免。 1) 讓每個線程使用不同的隨機數(shù)生成器實例。 2) 在所有調(diào)用外面加鎖。 3) 改用速度較慢但是線程安全的 normalvariate() 函數(shù)。

在 3.11 版更改: mu and sigma now have default arguments.

random.lognormvariate(mu, sigma)?

對數(shù)正態(tài)分布。 如果你采用這個分布的自然對數(shù),你將得到一個正態(tài)分布,平均值為 mu 和標準差為 sigmamu 可以是任何值,sigma 必須大于零。

random.normalvariate(mu=0.0, sigma=1.0)?

正態(tài)分布。 mu 是平均值,sigma 是標準差。

在 3.11 版更改: mu and sigma now have default arguments.

random.vonmisesvariate(mu, kappa)?

馮·米塞斯分布。 mu 是平均角度,以弧度表示,介于0和 2*pi 之間,kappa 是濃度參數(shù),必須大于或等于零。 如果 kappa 等于零,則該分布在 0 到 2*pi 的范圍內(nèi)減小到均勻的隨機角度。

random.paretovariate(alpha)?

帕累托分布。 alpha 是形狀參數(shù)。

random.weibullvariate(alpha, beta)?

威布爾分布。 alpha 是比例參數(shù),beta 是形狀參數(shù)。

替代生成器?

class random.Random([seed])?

該類實現(xiàn)了 random 模塊所用的默認偽隨機數(shù)生成器。

3.9 版后已移除: 在將來,seed 必須是下列類型之一: NoneType, int, float, str, bytesbytearray。

class random.SystemRandom([seed])?

使用 os.urandom() 函數(shù)的類,用從操作系統(tǒng)提供的源生成隨機數(shù)。 這并非適用于所有系統(tǒng)。 也不依賴于軟件狀態(tài),序列不可重現(xiàn)。 因此,seed() 方法沒有效果而被忽略。 getstate()setstate() 方法如果被調(diào)用則引發(fā) NotImplementedError。

關(guān)于再現(xiàn)性的說明?

有時能夠重現(xiàn)偽隨機數(shù)生成器給出的序列是很有用處的。 通過重用一個種子值,只要沒有運行多線程,相同的序列就應(yīng)當可在多次運行中重現(xiàn)。

大多數(shù)隨機模塊的算法和種子函數(shù)都會在 Python 版本中發(fā)生變化,但保證兩個方面不會改變:

  • 如果添加了新的播種方法,則將提供向后兼容的播種機。

  • 當兼容的播種機被賦予相同的種子時,生成器的 random() 方法將繼續(xù)產(chǎn)生相同的序列。

例子?

基本示例:

>>>
>>> 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 的示例,使用重新采樣和替換來估計一個樣本的均值的置信區(qū)間:

# 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}')

使用 重新采樣排列測試 來確定統(tǒng)計學顯著性或者使用 p-值 來觀察藥物與安慰劑的作用之間差異的示例:

# 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.')

多服務(wù)器隊列的到達時間和服務(wù)交付模擬:

from heapq import heapify, heapreplace
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
heapify(servers)
for i in range(1_000_000):
    arrival_time += expovariate(1.0 / average_arrival_interval)
    next_server_available = servers[0]
    wait = max(0.0, next_server_available - arrival_time)
    waits.append(wait)
    service_duration = max(0.0, gauss(average_service_time, stdev_service_time))
    service_completed = arrival_time + wait + service_duration
    heapreplace(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 撰寫的視頻教程,使用一些基本概念進行統(tǒng)計分析,包括模擬、抽樣、洗牌和交叉驗證。

Economics Simulation Peter Norvig 編寫的市場模擬,顯示了該模塊提供的許多工具和分布的有效使用( gauss 、 uniformsample 、 betavariatechoice 、 triangularrandrange )。

A Concrete Introduction to Probability (using Python) Peter Norvig 撰寫的教程,涵蓋了概率論基礎(chǔ)知識,如何編寫模擬,以及如何使用 Python 進行數(shù)據(jù)分析。

例程?

默認的 random() 返回在 0.0 ≤ x < 1.0 范圍內(nèi) 2??3 的倍數(shù)。 所有這些數(shù)值間隔相等并能精確表示為 Python 浮點數(shù)。 但是在此間隔上有許多其他可表示浮點數(shù)是不可能的選擇。 例如,0.05954861408025609 就不是 2??3 的整數(shù)倍。

以下規(guī)范程序采取了一種不同的方式。 在間隔上的所有浮點數(shù)都是可能的選擇。 它們的尾數(shù)取值來自 2?2 ≤ 尾數(shù) < 2?3 范圍內(nèi)整數(shù)的均勻分布。 指數(shù)取值則來自幾何分布,其中小于 -53 的指數(shù)的出現(xiàn)頻率為下一個較大指數(shù)的一半。

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)

該類中所有的 實值分布 都將使用新的方法:

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

該規(guī)范程序在概念上等效于在 0.0 ≤ x < 1.0 范圍內(nèi)對所有 2?1??? 的倍數(shù)進行選擇的算法。 所有這樣的數(shù)字間隔都相等,但大多必須向下舍入為最接近的 Python 浮點數(shù)表示形式。 (2?1??? 這個數(shù)值是等于 math.ulp(0.0) 的未經(jīng)正規(guī)化的最小正浮點數(shù)。)

參見

生成偽隨機浮點數(shù)值 為 Allen B. Downey 所撰寫的描述如何生成相比通過 random() 正常生成的數(shù)值更細粒度浮點數(shù)的論文。