random
--- 生成偽隨機數?
源碼: Lib/random.py
該模塊實(shí)現了各種分布的偽隨機數生成器。
對于整數,從范圍中有統一的選擇。 對于序列,存在隨機元素的統一選擇、用于生成列表的隨機排列的函數、以及用于隨機抽樣而無(wú)需替換的函數。
在實(shí)數軸上,有計算均勻、正態(tài)(高斯)、對數正態(tài)、負指數、伽馬和貝塔分布的函數。 為了生成角度分布,可以使用 von Mises 分布。
幾乎所有模塊函數都依賴(lài)于基本函數 random()
,它在半開(kāi)放區間 [0.0,1.0) 內均勻生成隨機浮點(diǎn)數。 Python 使用 Mersenne Twister 作為核心生成器。 它產(chǎn)生 53 位精度浮點(diǎn)數,周期為 2**19937-1 ,其在 C 中的底層實(shí)現既快又線(xiàn)程安全。 Mersenne Twister 是現存最廣泛測試的隨機數發(fā)生器之一。 但是,因為完全確定性,它不適用于所有目的,并且完全不適合加密目的。
這個(gè)模塊提供的函數實(shí)際上是 random.Random
類(lèi)的隱藏實(shí)例的綁定方法。 你可以實(shí)例化自己的 Random
類(lèi)實(shí)例以獲取不共享狀態(tài)的生成器。
如果你想使用自己設計的不同基礎生成器,類(lèi) Random
也可以作為子類(lèi):在這種情況下,重載 random()
、 seed()
、 getstate()
以及 setstate()
方法??蛇x地,新生成器可以提供 getrandbits()
方法——這允許 randrange()
在任意大的范圍內產(chǎn)生選擇。
random
模塊還提供 SystemRandom
類(lèi),它使用系統函數 os.urandom()
從操作系統提供的源生成隨機數。
警告
不應將此模塊的偽隨機生成器用于安全目的。 有關(guān)安全性或加密用途,請參閱 secrets
模塊。
參見(jiàn)
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 用于兼容的替代隨機數發(fā)生器,具有長(cháng)周期和相對簡(jiǎn)單的更新操作。
簿記功能?
- random.seed(a=None, version=2)?
初始化隨機數生成器。
如果 a 被省略或為
None
,則使用當前系統時(shí)間。 如果操作系統提供隨機源,則使用它們而不是系統時(shí)間(有關(guān)可用性的詳細信息,請參閱os.urandom()
函數)。如果 a 是 int 類(lèi)型,則直接使用。
對于版本2(默認的),
str
、bytes
或bytearray
對象轉換為int
并使用它的所有位。對于版本1(用于從舊版本的Python再現隨機序列),用于
str
和bytes
的算法生成更窄的種子范圍。在 3.2 版更改: 已移至版本2方案,該方案使用字符串種子中的所有位。
- random.getstate()?
返回捕獲生成器當前內部狀態(tài)的對象。 這個(gè)對象可以傳遞給
setstate()
來(lái)恢復狀態(tài)。
- random.setstate(state)?
state 應該是從之前調用
getstate()
獲得的,并且setstate()
將生成器的內部狀態(tài)恢復到getstate()
被調用時(shí)的狀態(tài)。
用于字節數據的函數?
- random.randbytes(n)?
生成 n 個(gè)隨機字節。
此方法不可用于生成安全憑據。 那應當使用
secrets.token_bytes()
。3.9 新版功能.
整數用函數?
- 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 asrange(0, 100, 1)
.在 3.2 版更改:
randrange()
在生成均勻分布的值方面更為復雜。 以前它使用了像``int(random()*n)``這樣的形式,它可以產(chǎn)生稍微不均勻的分布。在 3.12 版更改: Automatic conversion of non-integer types is no longer supported. Calls such as
randrange(10.0)
andrandrange(Fraction(10, 1))
now raise aTypeError
.
- random.randint(a, b)?
返回隨機整數 N 滿(mǎn)足
a <= N <= b
。相當于randrange(a, b+1)
。
- random.getrandbits(k)?
返回具有 k 個(gè)隨機比特位的非負 Python 整數。 此方法隨 MersenneTwister 生成器一起提供,其他一些生成器也可能將其作為 API 的可選部分提供。 在可能的情況下,
getrandbits()
會(huì )啟用randrange()
來(lái)處理任意大的區間。在 3.9 版更改: 此方法現在接受零作為 k 的值。
序列用函數?
- random.choice(seq)?
從非空序列 seq 返回一個(gè)隨機元素。 如果 seq 為空,則引發(fā)
IndexError
。
- random.choices(population, weights=None, *, cum_weights=None, k=1)?
從 population 中選擇替換,返回大小為 k 的元素列表。 如果 population 為空,則引發(fā)
IndexError
。如果指定了 weight 序列,則根據相對權重進(jìn)行選擇。 或者,如果給出 cum_weights 序列,則根據累積權重(可能使用
itertools.accumulate()
計算)進(jìn)行選擇。 例如,相對權重``[10, 5, 30, 5]``相當于累積權重``[10, 15, 45, 50]``。 在內部,相對權重在進(jìn)行選擇之前會(huì )轉換為累積權重,因此提供累積權重可以節省工作量。如果既未指定 weight 也未指定 cum_weights ,則以相等的概率進(jìn)行選擇。 如果提供了權重序列,則它必須與 population 序列的長(cháng)度相同。 一個(gè)
TypeError
指定了 weights 和 cum_weights 。weights 或 cum_weights 可使用
random()
所返回的能與float
值進(jìn)行相互運算的任何數字類(lèi)型(包括整數、浮點(diǎn)數、分數但不包括 decimal)。 權重值應當非負且為有限的數值。 如果所有的權重值均為零則會(huì )引發(fā)ValueError
。對于給定的種子,具有相等加權的
choices()
函數通常產(chǎn)生與重復調用choice()
不同的序列。choices()
使用的算法使用浮點(diǎn)運算來(lái)實(shí)現內部一致性和速度。choice()
使用的算法默認為重復選擇的整數運算,以避免因舍入誤差引起的小偏差。3.6 新版功能.
在 3.9 版更改: 如果所有權重均為負值則將引發(fā)
ValueError
。
- random.shuffle(x)?
就地將序列 x 隨機打亂位置。
要改變一個(gè)不可變的序列并返回一個(gè)新的打亂列表,請使用``sample(x, k=len(x))``。
請注意,即使對于小的
len(x)
,x 的排列總數也可以快速增長(cháng),大于大多數隨機數生成器的周期。 這意味著(zhù)長(cháng)序列的大多數排列永遠不會(huì )產(chǎn)生。 例如,長(cháng)度為2080的序列是可以在 Mersenne Twister 隨機數生成器的周期內擬合的最大序列。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.
返回包含來(lái)自總體的元素的新列表,同時(shí)保持原始總體不變。 結果列表按選擇順序排列,因此所有子切片也將是有效的隨機樣本。 這允許抽獎獲獎?wù)撸颖荆┍粍澐譃榇螵労偷诙@勝者(子切片)。
總體成員不必是 hashable 或 unique 。 如果總體包含重復,則每次出現都是樣本中可能的選擇。
重復的元素可以一個(gè)個(gè)地直接列出,或使用可選的僅限關(guān)鍵字形參 counts 來(lái)指定。 例如,
sample(['red', 'blue'], counts=[4, 2], k=5)
等價(jià)于sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5)
。要從一系列整數中選擇樣本,請使用
range()
對象作為參數。 對于從大量人群中采樣,這種方法特別快速且節省空間: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í)值分布。如常用數學(xué)實(shí)踐中所使用的那樣,函數形參以分布方程中的相應變量命名,大多數這些方程都可以在任何統計學(xué)教材中找到。
- random.random()?
返回 [0.0, 1.0) 范圍內的下一個(gè)隨機浮點(diǎn)數。
- random.uniform(a, b)?
返回一個(gè)隨機浮點(diǎn)數 N ,當
a <= b
時(shí)a <= N <= b
,當b < a
時(shí)b <= N <= a
。取決于等式
a + (b-a) * random()
中的浮點(diǎn)舍入,終點(diǎn)b
可以包括或不包括在該范圍內。
- random.triangular(low, high, mode)?
返回一個(gè)隨機浮點(diǎn)數 N ,使得
low <= N <= high
并在這些邊界之間使用指定的 mode 。 low 和 high 邊界默認為零和一。 mode 參數默認為邊界之間的中點(diǎn),給出對稱(chēng)分布。
- random.betavariate(alpha, beta)?
Beta 分布。 參數的條件是
alpha > 0
和beta > 0
。 返回值的范圍介于 0 和 1 之間。
- random.expovariate(lambd)?
指數分布。 lambd 是 1.0 除以所需的平均值,它應該是非零的。 (該參數本應命名為 “l(fā)ambda” ,但這是 Python 中的保留字。)如果 lambd 為正,則返回值的范圍為 0 到正無(wú)窮大;如果 lambd 為負,則返回值從負無(wú)窮大到 0。
- random.gammavariate(alpha, beta)?
Gamma 分布。 ( 不是 gamma 函數! ) 參數的條件是
alpha > 0
和beta > 0
。概率分布函數是:
x ** (alpha - 1) * math.exp(-x / beta) pdf(x) = -------------------------------------- math.gamma(alpha) * beta ** alpha
- random.gauss(mu=0.0, sigma=1.0)?
正態(tài)分布,也稱(chēng)高斯分布。 mu 為平均值,而 sigma 為標準差。 此函數要稍快于下面所定義的
normalvariate()
函數。多線(xiàn)程注意事項:當兩個(gè)線(xiàn)程同時(shí)調用此方法時(shí),它們有可能將獲得相同的返回值。 這可以通過(guò)三種辦法來(lái)避免。 1) 讓每個(gè)線(xiàn)程使用不同的隨機數生成器實(shí)例。 2) 在所有調用外面加鎖。 3) 改用速度較慢但是線(xiàn)程安全的
normalvariate()
函數。在 3.11 版更改: mu and sigma now have default arguments.
- random.lognormvariate(mu, sigma)?
對數正態(tài)分布。 如果你采用這個(gè)分布的自然對數,你將得到一個(gè)正態(tài)分布,平均值為 mu 和標準差為 sigma 。 mu 可以是任何值,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 是濃度參數,必須大于或等于零。 如果 kappa 等于零,則該分布在 0 到 2*pi 的范圍內減小到均勻的隨機角度。
- random.paretovariate(alpha)?
帕累托分布。 alpha 是形狀參數。
- random.weibullvariate(alpha, beta)?
威布爾分布。 alpha 是比例參數,beta 是形狀參數。
替代生成器?
- class random.SystemRandom([seed])?
使用
os.urandom()
函數的類(lèi),用從操作系統提供的源生成隨機數。 這并非適用于所有系統。 也不依賴(lài)于軟件狀態(tài),序列不可重現。 因此,seed()
方法沒(méi)有效果而被忽略。getstate()
和setstate()
方法如果被調用則引發(fā)NotImplementedError
。
關(guān)于再現性的說(shuō)明?
有時(shí)能夠重現偽隨機數生成器給出的序列是很有用處的。 通過(guò)重用一個(gè)種子值,只要沒(méi)有運行多線(xiàn)程,相同的序列就應當可在多次運行中重現。
大多數隨機模塊的算法和種子函數都會(huì )在 Python 版本中發(fā)生變化,但保證兩個(gè)方面不會(huì )改變:
如果添加了新的播種方法,則將提供向后兼容的播種機。
當兼容的播種機被賦予相同的種子時(shí),生成器的
random()
方法將繼續產(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 的示例,使用重新采樣和替換來(lái)估計一個(gè)樣本的均值的置信區間:
# 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}')
使用 重新采樣排列測試 來(lái)確定統計學(xué)顯著(zhù)性或者使用 p-值 來(lái)觀(guān)察藥物與安慰劑的作用之間差異的示例:
# 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ù)器隊列的到達時(shí)間和服務(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)])
參見(jiàn)
Statistics for Hackers Jake Vanderplas 撰寫(xiě)的視頻教程,使用一些基本概念進(jìn)行統計分析,包括模擬、抽樣、洗牌和交叉驗證。
Economics Simulation Peter Norvig 編寫(xiě)的市場(chǎng)模擬,顯示了該模塊提供的許多工具和分布的有效使用( gauss 、 uniform 、 sample 、 betavariate 、 choice 、 triangular 和 randrange )。
A Concrete Introduction to Probability (using Python) Peter Norvig 撰寫(xiě)的教程,涵蓋了概率論基礎知識,如何編寫(xiě)模擬,以及如何使用 Python 進(jìn)行數據分析。
例程?
默認的 random()
返回在 0.0 ≤ x < 1.0 范圍內 2??3 的倍數。 所有這些數值間隔相等并能精確表示為 Python 浮點(diǎn)數。 但是在此間隔上有許多其他可表示浮點(diǎn)數是不可能的選擇。 例如,0.05954861408025609
就不是 2??3 的整數倍。
以下規范程序采取了一種不同的方式。 在間隔上的所有浮點(diǎn)數都是可能的選擇。 它們的尾數取值來(lái)自 2?2 ≤ 尾數 < 2?3 范圍內整數的均勻分布。 指數取值則來(lái)自幾何分布,其中小于 -53 的指數的出現頻率為下一個(gè)較大指數的一半。
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)
該類(lèi)中所有的 實(shí)值分布 都將使用新的方法:
>>> fr = FullRandom()
>>> fr.random()
0.05954861408025609
>>> fr.expovariate(0.25)
8.87925541791544
該規范程序在概念上等效于在 0.0 ≤ x < 1.0 范圍內對所有 2?1??? 的倍數進(jìn)行選擇的算法。 所有這樣的數字間隔都相等,但大多必須向下舍入為最接近的 Python 浮點(diǎn)數表示形式。 (2?1??? 這個(gè)數值是等于 math.ulp(0.0)
的未經(jīng)正規化的最小正浮點(diǎn)數。)
參見(jiàn)
生成偽隨機浮點(diǎn)數值 為 Allen B. Downey 所撰寫(xiě)的描述如何生成相比通過(guò) random()
正常生成的數值更細粒度浮點(diǎn)數的論文。