Python STL random
作用:實現了多種類型的偽隨機數生成器。
Python版本:1.4及以後版本
random模塊基幹Mersenne IVister算法提供了一個快速偽隨機數生成器。原先開發這個生成器是為了向蒙特卡洛模擬生成輸入,Mersenne Twister算法會生成有一個大周期的近均勻分 布的數,以適用於各種類型的應用。
生成隨機數
random()函數從所生成的序列返回下一個隨機的浮點數值。返回的所有值都落在0< n <1.0區間內。
import random for i in xrange(5): print '%04.3f' % random.random(), print
重復運行這個程序會生成不同的數字序列。
0.929 0.100 0.906 0.075 0.439
[Finished in 0.1s]
要生成一個指定數值區間內的數,則要使用uniform()。
import random
for i in xrange(5):
print '%04.3f' % random.uniform(1, 100),
print
傳入最小值和最大值,uniform()會使用公式min + (max - min) * random來調整random() 的返回值。
4.679 66.794 19.423 44.725 5.482
[Finished in 0.1s]
指定種子
每次調用random會生成不同的值,在一個非常大的周期之後數字才會重復。這對於生成惟一值或變化的值很有用,不過有些情況下可能需要提供相同的數據集,從而以相同的方式處理。對此,一種技術是使用一個程序來生成隨機值,並保存這些隨機值,以便通過一個單獨的步驟另行處理。不過,這對於量很大的數據來說可能並不實用,所以random包含了一個seed() 函數,用來初始化偽隨機數生成器,使它能生成一個期望的值集。
import random random.seed(1) for i in xrange(5): print '%04.3f' % random.random(), print
種子(seed)值會控制生成偽隨機數所用公式產生的第一個值,由於公式是確定性的,改變種子後也就設置了要生成的整個序列。seed的參數可以是任意可散列對象。默認為使用一個平臺特定的隨機源(如杲有的話)。否則,如果沒有這樣一個隨機源,則會使用當前時間。
0.134 0.847 0.764 0.255 0.495
[Finished in 0.1s]
保存狀態
random使用的偽隨機算法的內部狀態可以保存,並用於控制後續各輪生成的隨機數,繼續生成隨機數之前恢復前一個狀態,這會減少由之前輸入得到重復的值或值序列的可能性。getstate函數會返回一些數據,以後可以用setstate利用這些數據重新初始化偽隨機數生成器。
import random
import os
import cPickle as pickle
if os.path.exists('state.dat'):
# Restore the previously saved state
print 'Found state.dat, initializing random module'
with open('state.dat', 'rb') as f:
state = pickle.load(f)
random.setstate(state)
else:
# Use a well-known start state
print 'No state.dat, seeding'
random.seed(1)
# Produce random values
for i in xrange(3):
print '%04.3f' % random.random(),
print
# Save state for next time
with open('state.dat', 'wb') as f:
pickle.dump(random.getstate(), f)
# Produce more random values
print '\nAfter saving state:'
for i in xrange(3):
print '%04.3f' % random.random(),
print
getstate()返回的數據是一個實現細節,所以這個例子用pickle將數據保存到一個文件,不過可以把它當作一個黑盒。如果程序開始時這個文件存在,則加載原來的狀態並繼續。每次運行時都會在保存狀態之前以及之後生成一些數,以展示恢復狀態會導致生成器再次生成同樣的值。
No state.dat, seeding
0.134 0.847 0.764
After saving state:
0.255 0.495 0.449
[Finished in 0.1s]
Found state.dat, initializing random module
0.255 0.495 0.449
After saving state:
0.652 0.789 0.094
[Finished in 0.1s]
Found state.dat, initializing random module
0.652 0.789 0.094
After saving state:
0.028 0.836 0.433
[Finished in 0.1s]
隨機整數
random將生成浮點數。可以把結果轉換為整數,不過直接使用randint生成整數會更方便。
import random
print '[1, 100]:',
for i in xrange(3):
print random.randint(1, 100),
print '\n[-5, 5]:',
for i in xrange(3):
print random.randint(-5, 5),
print
randint的參數是值的閉區間的兩端,這些數可以是正數或負數,不過第一個值要小於第二個值.
[1, 100]: 35 39 28
[-5, 5]: -3 4 4
[Finished in 0.1s]
randrange是從區間選擇值的一種更一般的形式。
import random
for i in xrange(3):
print random.randrange(0, 101, 5),
print
除了開始值(start)和結束值(stop), randrange還支持一個步長 step 參數,所以它完全等價於從range(start,stop,step)選擇一個隨機值。不過randrange更高效,因為它並沒有真正構造區間。
15 25 85
[Finished in 0.1s]
選擇隨機元素
隨機數生成器有一種常見用法,即從一個枚舉值序列中選擇元素,即使這些值並不是數字。random包括一個choice函數,可以在一個序列中隨機選擇。下面這個例子模擬拋硬幣10000 次,來統計多少次面朝上,多少次面朝下,
import random
import itertools
outcomes = { 'heads':0,
'tails':0,
}
sides = outcomes.keys()
for i in range(10000):
outcomes[ random.choice(sides) ] += 1
print 'Heads:', outcomes['heads']
print 'Tails:', outcomes['tails']
由於只允許兩個結果,所以不必使用數字然後再進行轉換,這裏對choice使用了單詞 “heads”(表示面朝上)和“tails”(表示面朝下)。結果以表格形式存儲在一個字典中,使用結果名作為鍵。
Heads: 5042
Tails: 4958
[Finished in 0.1s]
排列
要模擬一個撲克牌遊戲,需要把一副牌混起來,然後向玩家發牌,同一張牌不能多次使用。使用choice可能導致同一張牌被發出兩次,所以可以用shuffle()來洗牌,然後在發各張牌時刪除所發的牌。
import random
import itertools
FACE_CARDS = ('J', 'Q', 'K', 'A')
SUITS = ('H', 'D', 'C', 'S')
def new_deck():
return list(itertools.product(
itertools.chain(xrange(2, 11), FACE_CARDS),
SUITS,
))
def show_deck(deck):
p_deck = deck[:]
while p_deck:
row = p_deck[:13]
p_deck = p_deck[13:]
for j in row:
print '%2s%s' % j,
print
# Make a new deck, with the cards in order
deck = new_deck()
print 'Initial deck:'
show_deck(deck)
# Shuffle the deck to randomize the order
random.shuffle(deck)
print '\nShuffled deck:'
show_deck(deck)
# Deal 4 hands of 5 cards each
hands = [ [], [], [], [] ]
for i in xrange(5):
for h in hands:
h.append(deck.pop())
# Show the hands
print '\nHands:'
for n, h in enumerate(hands):
print '%d:' % (n+1),
for c in h:
print '%2s%s' % c,
print
# Show the remaining deck
print '\nRemaining deck:'
show_deck(deck)
這些撲克牌表示為元組,由面值和一個表示花色的字母組成。要創建已發出“一手牌”,可以一次向4個列表分別增加一張牌,然後從這副牌中將其刪除,使這些牌不會再次發出。
Initial deck:
2H 2D 2C 2S 3H 3D 3C 3S 4H 4D 4C 4S 5H
5D 5C 5S 6H 6D 6C 6S 7H 7D 7C 7S 8H 8D
8C 8S 9H 9D 9C 9S 10H 10D 10C 10S JH JD JC
JS QH QD QC QS KH KD KC KS AH AD AC AS
Shuffled deck:
3C 8S QC 5D 2C 9H QH KC AS 4D 5H 10D QS
3S 5S JS AD QD 5C KS 8H 4S 3H 7S 10C 6D
3D 2S 7D 4C 2H 9S 2D 6S 4H 6C AC JD 8D
10H KH KD JC 6H 9C JH 7C 10S 8C AH 9D 7H
Hands:
1: 7H 10S 6H 10H 6C
2: 9D 7C JC 8D 4H
3: AH JH KD JD 6S
4: 8C 9C KH AC 2D
Remaining deck:
3C 8S QC 5D 2C 9H QH KC AS 4D 5H 10D QS
3S 5S JS AD QD 5C KS 8H 4S 3H 7S 10C 6D
3D 2S 7D 4C 2H 9S
[Finished in 0.1s]
采樣
很多模擬需要從大量輸入值中得到隨機樣本sample()函數可以生成無重復值的樣本,且不會修改輸入序列。下面的例子會打印系統字典中單詞的一個隨機樣本。
import random
with open('words.txt', 'rt') as f:
words = f.readlines()
words = [ w.rstrip() for w in words ]
for w in random.sample(words, 5):
print w
生成結果集的算法會考慮輪入的規模和所請求的樣本,從而盡可能髙效地生成結果。
docibility
Ituraean
youdendrift
sporidium
pansylike
[Finished in 0.1s]
Ituraean
pansylike
jigamaree
docibility
readingdom
[Finished in 0.1s]
多個並發生成器
除了模塊級函數,random還包括一個Random類來管理多個隨機數生成器的內部狀態。之前介紹的所有函數都可以作為Random實例的方法得到,而且各個實例可以單獨初始化和使用,而不會與其他實例返回的值相互幹擾。
import random
import time
print 'Default initializiation:\n'
r1 = random.Random()
r2 = random.Random()
for i in xrange(3):
print '%04.3f %04.3f' % (r1.random(), r2.random())
print '\nSame seed:\n'
seed = time.time()
r1 = random.Random(seed)
r2 = random.Random(seed)
for i in xrange(3):
print '%04.3f %04.3f' % (r1.random(), r2.random())
如杲系統上設置了很好的內置隨機值種子,不同實例會有惟一的初始狀態。不過,如果沒有一個好的平臺隨機值生成器,不同實例往往會用當前時間作為種子,因此會生成相同的值。
Default initializiation:
0.189 0.307
0.466 0.328
0.020 0.757
Same seed:
0.510 0.510
0.981 0.981
0.679 0.679
[Finished in 0.1s]
為了確保生成器從隨機周期的不同部分生成值,可以使用jumpahead調整其中一個生成器的初始狀態。
Default initializiation:
0.189 0.307
0.466 0.328
0.020 0.757
Same seed:
0.510 0.510
0.981 0.981
0.679 0.679
[Finished in 0.1s]
SystemRandom
有些操作系統提供了一個隨機數生成器,可以訪問更多能夠引入生成器的信息源。 random通過SystemRandom類提供了這個特性,這個類與Random的API相同,不過使用os.urandom()生成值,這構成了所有其他算法的基礎。
import random
import time
print 'Default initializiation:\n'
r1 = random.SystemRandom()
r2 = random.SystemRandom()
for i in xrange(3):
print '%04.3f %04.3f' % (r1.random(), r2.random())
print '\nSame seed:\n'
seed = time.time()
r1 = random.SystemRandom(seed)
r2 = random.SystemRandom(seed)
for i in xrange(3):
print '%04.3f %04.3f' % (r1.random(), r2.random())
SystemRandom產生的序列是不可再生的,因為其隨機性來自系統,而不是來自軟件狀態 (實際上,seed()和setstate()根本不起作用).
Default initializiation:
0.945 0.201
0.767 0.295
0.984 0.383
Same seed:
0.584 0.324
0.598 0.624
0.400 0.310
[Finished in 0.1s]
非均勻分布
random生成的值為均勻分布,這對於很多用途來說非常有用,不過,另外一些分布可以更準確地對特定情況建模。random模塊還包含一些函數來生成這樣一些分布的值。這裏將列出 這些分布,但是並不打算詳細介紹,因為它們往往只在特定條件下使用,而且需要更復雜的例 子來說明。
正態分布
正態分布(normal distribution)常用於非均勻的連續值,如梯度、髙度、重置等等.正態 分布產生的曲線有一個獨特形狀,所以被昵稱為“鐘形曲線”。random包含兩個函數可以生成 正態分布的值,分別是normalvariate和稍快一些的gauss。(正態分布也稱為髙斯分布。) 還有一個相關的函數lognormvariate,它可以生成對數呈正態分布的偽隨機值。對數正態分布適用於多個不交互隨機變量的積。
近似分布
三角分布用於小樣本的近似分布。三角分布的“曲線”中,低點在已知的最小和最大值,在模式值處有一個髙點,這要根據“最接近”的結果(由triangularO的模式參數反映)來估計。
指數分布
expovariate可以生成一個指數分布,這對於模擬到達或間隔時間值用於齊次泊松過程會很有用,如放射衰變速度或到達Web服務器的請求。很多可觀察的現象都適用帕累托分布或冪律分布,這個分布因Chris Anderson的“長尾效應”而普及。paretovariatc()函數對於槙擬資源分配很有用(人的財宮、音樂家的需求、對博客的關註,等等)。
角分布
米塞斯分布或圓正態分布(由vonmisesvariate生成)用於計算周期值的概率,如角度、 日歷日期和時間。
大小分布
betavariate生成Beta分布的值,常用於貝葉斯統計和應用,如任務持續時間建模。 gammavariate()生成的伽瑪分布用於對事物的大小建模,如等待時間、雨量和計算錯誤。 weibullvariate計算的韋伯分布用於故障分析、工業工程和天氣預報。它描述了粒子或其 他離散對象的大小分布。
Python STL random