1. random偽亂數生成器
random模塊基于Mersenne Twister演算法提供了一個快速偽亂數生成器,原來開發這個生成器是為了向蒙特卡洛模擬生成輸入,Mersenne Twister演算法會生成大周期近均勻分布的數,因此適用于大量不同型別的應用,
1.1 生成亂數
random()函式從所生成的序列回傳下一個隨機的浮點值,回傳的所有值都落在0<=n<1.0區間內,
import random for i in range(5): print('%04.3f' % random.random(), end=' ') print()
重復運行這個程式會產生不同的數字序列,

要生成一個指定數值區間內的數,則要使用uniform(),
import random for i in range(5): print('{:04.3f}'.format(random.uniform(1, 100)), end=' ') print()
傳入最小值和最大值,uniform()會使用公式min+(max-min)*random()來調整random()的回傳值,

1.2 指定種子
每次呼叫random()都會生成不同的值,并且在一個非常大的周期之后數字才會重復,這對于生成唯一值或變化的值很有用,不過有些情況下可能需要提供相同的資料集,從而以不同的方式處理,對此,一種技術是使用一個程式生成隨機值,并保存這些隨機值,以便在另一個步驟中再做處理,不過,這對于量很大的資料來說可能并不實用,所以random包含了一個seed()函式,可以用來初始化偽亂數生成器,使它能生成一個期望的值集,
import random random.seed(1) for i in range(5): print('{:04.3f}'.format(random.random()), end=' ') print()
種子(seed)值會控制由公式生成的第一個值,該公式可用來生成偽亂數,由于公式是確定的,所以改變種子后便設定了將生成的整個序列,seed()的引數可用是任意的可散列物件,默認為使用一個平臺特定的隨機源(如果有的話),但如果沒有這樣一個隨機源,則使用當前時間,

1.3 保存狀態
random()使用的偽隨機演算法的內部狀態可以保存,并用于控制后續生成的亂數,如果在繼續生成亂數之前恢復前一個狀態,則會減少出現重復的可能性,即避免出現之前輸入中重復的值或值序列,getstate()函式會回傳一些資料,以后可以借助setstate()利用這些資料重新初始化偽亂數生成器,
import random import os import 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 range(3): print('{:04.3f}'.format(random.random()), end=' ') 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 range(3): print('{:04.3f}'.format(random.random()), end=' ') print()
getstate()回傳的資料是一個實作細節,所以這個例子用pickle將資料保存到一個檔案;否則,它會把偽亂數生成器當作一個黑盒,如果程式開始時這個檔案存在,則加載原來的狀態并繼續,每次運行時都會在保存狀態之前和之后生成一些數,以展示恢復狀態會使生成器再次生成同樣的值,
第一次:

第二次:

1.4 隨機整數
random()將生成浮點數,可以把結果轉換為整數,不過直接使用randint()生成整數會更方便,
import random print('[1, 100]:', end=' ') for i in range(3): print(random.randint(1, 100), end=' ') print('\n[-5, 5]:', end=' ') for i in range(3): print(random.randint(-5, 5), end=' ') print()
randint()的引數是值的閉區間的兩端,這些數可以是正數或負數,不過第一個值要小于第二個值,

randrange()是從區間選擇值的一種更一般的形式,
import random for i in range(3): print(random.randrange(0, 101, 5), end=' ') print()
除了開始值(start)和結束值(stop),randrange()還支持一個步長(step)引數,所以它完全等價于從range(start,stop,step)選擇一個隨機值,不過randrange更高效,因為它并沒有真正構造區間,

1.5 選擇隨機元素
亂數生成器有一種常見用法,即從一個列舉值序列中選擇元素,即使這些值并不是數字,random包括一個choice()函式,可以從一個序列中隨機選擇,下面這個例子模擬硬幣10000此來統計多少次面朝上,多少次面朝下,
import random import itertools outcomes = { 'heads': 0, 'tails': 0, } sides = list(outcomes.keys()) for i in range(10000): outcomes[random.choice(sides)] += 1 print('Heads:', outcomes['heads']) print('Tails:', outcomes['tails'])
由于只允許兩個結果,所以不必使用數字然后再進行轉換,這里對choice()使用了單詞“heads”(表示面朝上)和“tails”(表示面朝下),結果以表格形式存盤在一個字典中,使用結果名作為鍵,

1.6 排列
要模擬一個撲克牌游戲,需要把一副牌混起來,然后向玩家發牌,同一張牌不能多次使用,使用choice()可能導致同一張牌被發出兩次,所以,可以用shuffle()來洗牌,然后在發各張牌時洗掉所發的牌,
import random import itertools FACE_CARDS = ('J', 'Q', 'K', 'A') SUITS = ('H', 'D', 'C', 'S') def new_deck(): return [ # Always use 2 places for the value, so the strings # are a consistent width. '{:>2}{}'.format(*c) for c in itertools.product( itertools.chain(range(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(j, end=' ') 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 range(5): for h in hands: h.append(deck.pop()) # Show the hands print('\nHands:') for n, h in enumerate(hands): print('{}:'.format(n + 1), end=' ') for c in h: print(c, end=' ') print() # Show the remaining deck print('\nRemaining deck:') show_deck(deck)
這些撲克牌被表示為字串,包括面值和一個表示花色的字母,要創建發出的“一手牌”,可以一次向4個串列分別增加一張牌,然后從這副牌中將發出的牌洗掉,使這些牌不會再次發出,

1.7 采樣
很多模擬需要從大量輸入值中得到隨機樣本,sample()函式可以生成無重復值的樣本,并且不會修改輸入序列,下面的例子會列印系統字典中單詞的一個隨機樣本,
words.txt
pear
apricot
grape
pineapple
apple
peach
banana
plum
watermelon
lemon
orange
mango
strawberry
Demo.py
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)
第一次:

第二次:

1.8 多個并發生成器
除了模塊級函式,random還包括一個Random類以管理多個亂數生成器的內部狀態,之前介紹的所有函式都可以作為Random實體的方法得到,并且每個實體都可以被單獨初始化和使用,而不會干擾其他實體回傳的值,
import random import time print('Default initializiation:\n') r1 = random.Random() r2 = random.Random() for i in range(3): print('{:04.3f} {:04.3f}'.format(r1.random(), r2.random())) print('\nSame seed:\n') seed = time.time() r1 = random.Random(seed) r2 = random.Random(seed) for i in range(3): print('{:04.3f} {:04.3f}'.format(r1.random(), r2.random()))
如果系統上設定了很好的原生隨機值種子,那么實體會有獨特的初始狀態,不過,如果沒有一個好的平臺隨機值生成器,那么不同實體往往會以當前時間作為種子,并因此生成相同的值,

1.9 SystemRandom
有些作業系統提供了一個亂數生成器,可以訪問更多能引入生成器的資訊源,random通SystemRandom類提供了這個特性,該類與Random的API相同,不過使用os.urandom()生成值,該值會構成所有其他演算法的基礎,
import random import time print('Default initializiation:\n') r1 = random.SystemRandom() r2 = random.SystemRandom() for i in range(3): print('{:04.3f} {:04.3f}'.format(r1.random(), r2.random())) print('\nSame seed:\n') seed = time.time() r1 = random.SystemRandom(seed) r2 = random.SystemRandom(seed) for i in range(3): print('{:04.3f} {:04.3f}'.format(r1.random(), r2.random()))
SystemRandom產生的序列是不可再生的,因為其隨機性來自系統,而不是來自軟體狀態(實際上,seed()和setstate()根本不起作用),

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/181827.html
標籤:Python
上一篇:【2020Python修煉記7】Python語法入門—基本資料型別_數字型別(整型+浮點型)
下一篇:Python—行程間通信
