標籤:軟體 initial val blog 程式 time() 故障分析 使用 選擇
作用:實現了多種類型的偽隨機數產生器。
Python版本:1.4及以後版本
random模組基幹Mersenne IVister演算法提供了一個快速偽隨機數產生器。原先開發這個產生器是為了向蒙特卡洛類比產生輸入,Mersenne Twister演算法會產生有一個大周期的近均勻分 布的數,以適用於各種類型的應用。
產生隨機數
random()函數從所產生的序列返回下一個隨機的浮點數值。返回的所有值都落在0< n <1.0區間內。
import randomfor 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 randomfor 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 randomrandom.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 randomimport osimport cPickle as pickleif 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 valuesfor i in xrange(3): print '%04.3f' % random.random(),print# Save state for next timewith open('state.dat', 'wb') as f: pickle.dump(random.getstate(), f)# Produce more random valuesprint '\nAfter saving state:'for i in xrange(3): print '%04.3f' % random.random(),print
getstate()返回的資料是一個實現細節,所以這個例子用pickle將資料儲存到一個檔案,不過可以把它當作一個黑盒。如果程式開始時這個檔案存在,則載入原來的狀態並繼續。每次運行時都會在儲存狀態之前以及之後產生一些數,以展示恢複狀態會導致產生器再次產生同樣的值。
No state.dat, seeding0.134 0.847 0.764After saving state:0.255 0.495 0.449[Finished in 0.1s]Found state.dat, initializing random module0.255 0.495 0.449After saving state:0.652 0.789 0.094[Finished in 0.1s]Found state.dat, initializing random module0.652 0.789 0.094After saving state:0.028 0.836 0.433[Finished in 0.1s]
隨機整數
random將產生浮點數。可以把結果轉換為整數,不過直接使用randint產生整數會更方便。
import randomprint '[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 randomfor 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 randomimport itertoolsoutcomes = { 'heads':0, 'tails':0, }sides = outcomes.keys()for i in range(10000): outcomes[ random.choice(sides) ] += 1print 'Heads:', outcomes['heads']print 'Tails:', outcomes['tails']
由於只允許兩個結果,所以不必使用數字然後再進行轉換,這裡對choice使用了單詞 “heads”(表示面朝上)和“tails”(表示面朝下)。結果以表格形式儲存在一個字典中,使用結果名作為鍵。
Heads: 5042Tails: 4958[Finished in 0.1s]
排列
要類比一個撲克牌遊戲,需要把一副牌混起來,然後向玩家發牌,同一張牌不能多次使用。使用choice可能導致同一張牌被發出兩次,所以可以用shuffle()來洗牌,然後在發各張牌時刪除所發的牌。
import randomimport itertoolsFACE_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 orderdeck = new_deck()print 'Initial deck:'show_deck(deck)# Shuffle the deck to randomize the orderrandom.shuffle(deck)print '\nShuffled deck:'show_deck(deck)# Deal 4 hands of 5 cards eachhands = [ [], [], [], [] ]for i in xrange(5): for h in hands: h.append(deck.pop())# Show the handsprint '\nHands:'for n, h in enumerate(hands): print '%d:' % (n+1), for c in h: print '%2s%s' % c, print # Show the remaining deckprint '\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 ASShuffled 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 8D10H KH KD JC 6H 9C JH 7C 10S 8C AH 9D 7HHands:1: 7H 10S 6H 10H 6C2: 9D 7C JC 8D 4H3: AH JH KD JD 6S4: 8C 9C KH AC 2DRemaining 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 randomwith 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
產生結果集的演算法會考慮輪入的規模和所請求的樣本,從而儘可能髙效地產生結果。
docibilityIturaeanyoudendriftsporidiumpansylike[Finished in 0.1s]Ituraeanpansylikejigamareedocibilityreadingdom[Finished in 0.1s]
多個並發產生器
除了模組層級函數,random還包括一個Random類來管理多個隨機數產生器的內部狀態。之前介紹的所有函數都可以作為Random執行個體的方法得到,而且各個執行個體可以單獨初始化和使用,而不會與其他執行個體返回的值相互幹擾。
import randomimport timeprint '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.3070.466 0.3280.020 0.757Same seed:0.510 0.5100.981 0.9810.679 0.679[Finished in 0.1s]
為了確保產生器從隨機周期的不同部分產生值,可以使用jumpahead調整其中一個產生器的初始狀態。
Default initializiation:0.189 0.3070.466 0.3280.020 0.757Same seed:0.510 0.5100.981 0.9810.679 0.679[Finished in 0.1s]
SystemRandom
有些作業系統提供了一個隨機數產生器,可以訪問更多能夠引入產生器的資訊源。 random通過SystemRandom類提供了這個特性,這個類與Random的API相同,不過使用os.urandom()產生值,這構成了所有其他演算法的基礎。
import randomimport timeprint '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.2010.767 0.2950.984 0.383Same seed:0.584 0.3240.598 0.6240.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