首頁 > 軟體

Python亂數種子(random seed)的使用

2021-07-28 16:00:38

在科學技術和機器學習等其他演演算法相關任務中,我們經常需要用到亂數,為了把握亂數的生成特性,從亂數的隨機無序中獲得確定和秩序。我們可以利用亂數種子(random seed)來實現這一目標,亂數種子,可以使得引入了亂數的整個程式,在多次執行中得到確定的,一致的結果。

很多博文談到亂數種子,只是簡單論及,利用亂數種子,可以每次生成相同的亂數。想真正用好掌握它,對此很容易產生疑惑,生成相同的亂數數怎麼個相同法?亂數種子又作何用處?

1. 亂數種子

下面我們從範例中揭開亂數種子的神祕面紗:

import random

# print(help(random))

def test_random_seed_in_std_lib(seed=0, cnt=3):
    random.seed(seed)
    print("test seed: ", seed)
    for _ in range(cnt):
        print(random.random())
        print(random.randint(0,100))
        print(random.uniform(1, 10))
        print('n')
test_random_seed_in_std_lib()
test seed:  0
0.8444218515250481
97
9.01219528753418

0.04048437818077755
65
5.373349269065314

0.9182343317851318
38
9.710199954281542
test_random_seed_in_std_lib()
test seed:  0
0.8444218515250481
97
9.01219528753418

0.04048437818077755
65
5.373349269065314

0.9182343317851318
38
9.710199954281542
test_random_seed_in_std_lib(99)
test seed:  99
0.40397807494366633
25
6.39495190686897

0.23026272839629136
17
7.8388969285727015

0.2511510083752201
49
5.777313434770537

通過兩次執行以上程式,我們得到相同的結果,這說明了以下幾點:

  1. 在確定了一次亂數種子後,亂數函數,無論任何分佈任何型別,在多次重複呼叫中(for迴圈)生成的亂數不同;
  2. 當再次宣告相同的亂數種子時(第二次呼叫test_random_seed_in_std_lib函數,random.seed(seed)這一行),亂數將從「頭」開始, 按相同的順序生成亂數。這裡的「頭」,即是random.seed(seed)宣告後,亂數函數的首次呼叫;
  3. 若指定不同的亂數種子(seed=99),無論任何亂數函數,生成的亂數將不同於,之前的(亂數種子為0)的執行結果。
  4. 上面的幾點解釋了亂數種子可以使得每次生成相同亂數的具體含義。這裡的相同,其實還有一種更普遍的內涵,即環境獨立和跨平臺。上面的實驗,在任何電腦或主機,執行以上程式碼,可以復現完全一致的結果。

以上幾點囊括了亂數種子的基本特性,下面我們來對numpy中的亂數種子作進一步的拓展研究。

2. numpy中的亂數種子

import numpy as np
def test_numpy_random_seed(seed=0, cnt=3):
    np.random.seed(seed)
    print("test numpy seed: ", seed)
    for _ in range(cnt):
        print(np.random.random())
        print(np.random.randn(1, 5))
        print(np.random.uniform(1, 10, 5))
        print('n')

多次執行以上的test_numpy_random_seed函數,你可以觀察到與使用random模組時相似的情形,進一步驗證了我們總結的關於亂數種子的特性。

此外,我們可以對多維亂陣列做一些有益的探索:

def test_mult_shape(seed=0):
    np.random.seed(seed)
    print(np.random.randn(1, 3))
    print(np.random.randn(1, 2))

    np.random.seed(seed)
    print(np.random.randn(2, 5))
test_mult_shape()
[[1.76405235 0.40015721 0.97873798]]
[[2.2408932  1.86755799]]
[[ 1.76405235  0.40015721  0.97873798  2.2408932   1.86755799]
 [-0.97727788  0.95008842 -0.15135721 -0.10321885  0.4105985 ]]

執行test_mult_shape函數,我們發現,設定相同的亂陣列,兩次執行兩個一行的多維正態分佈的結果,與一次執行兩行的多維正態分佈的結果的第一行完全相同。

這個結果,說明了對相同型別的亂數分佈,形狀特徵不會影響分佈的生成秩序,程式中,np.random.randn(1, 2),這一行不像是第二次執行多維正態分佈的亂陣列,它"幾乎"是字尾於它的前一行一次性生成的。

3. 亂數「順序」的奧祕

至此,我們對亂數生成順序有了初步印象,但是這裡的順序,其實比我們的樸素觀察更復雜,我們來進一步考察這一點。

def test_numpy_random_seed_order(seed=0):
    np.random.seed(seed)
    print(np.random.random())
    # print(np.random.randint(1, 10))
    print(np.random.randn(1, 5))


    np.random.seed(seed)
    print(np.random.randn(2, 5))
test_numpy_random_seed_order()
0.5488135039273248
[[ 0.74159174  1.55291372 -2.2683282   1.33354538 -0.84272405]]
[[ 1.76405235  0.40015721  0.97873798  2.2408932   1.86755799]
 [-0.97727788  0.95008842 -0.15135721 -0.10321885  0.4105985 ]]

執行以上程式,我們看到,設定了相同的亂數種子,np.random.randn(1, 5)看起來是第一次執行多維正態分佈陣列,實際上並不是,np.random.randn(2, 5)才是真正的第一次執行多維正態分佈亂陣列。

這說明,前面的np.random.random()對np.random.randn產生了干擾,使得這次正態分佈的亂陣列中的任何一個數,都不在np.random.randn(2, 5)中,這樣它顯示了一種不可把握的隨機性。

我們可以把這一點考察得更加深入一點:

def test_numpy_random_seed_order_further(seed=0, randint_high=10):
    np.random.seed(seed)
    print(np.random.randint(1, randint_high))
    print(np.random.randn(1, 5))


    np.random.seed(seed)
    print(np.random.randn(2, 5))
test_numpy_random_seed_order_further()
6
[[ 0.11849646  0.11396779  0.37025538  1.04053075 -1.51698273]]
[[ 1.76405235  0.40015721  0.97873798  2.2408932   1.86755799]
 [-0.97727788  0.95008842 -0.15135721 -0.10321885  0.4105985 ]]
test_numpy_random_seed_order_further(randint_high=5)
1
[[ 1.12279492  0.30280522  0.07085926  0.07304142 -1.42232584]]
[[ 1.76405235  0.40015721  0.97873798  2.2408932   1.86755799]
 [-0.97727788  0.95008842 -0.15135721 -0.10321885  0.4105985 ]]

緊接上面對亂數干擾項對考察,我們看到,這次我們改變了干擾項亂數生成器,np.random.randn(1, 5)的生成結果不同於test_numpy_random_seed_order中同一行的執行結果。

另外,兩次設定不同的randint的右邊界,np.random.randn(1, 5)生成的結果也全然不同,這說明了np.random.randint設定不同的引數,即是全然不同的亂數發生器。這一點,也不難在其他型別的亂數分佈中得到驗證。

到此這篇關於Python亂數種子(random seed)的使用的文章就介紹到這了,更多相關Python亂數種子內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com