[Py 百日馬 Day 4-1] random module 常見方法 - 產生隨機數與亂數取樣/排序


Posted by Laihan on 2022-02-03

在 Python 中想要隨機產生某數或抽籤功能可以使用 random 模組,這模組可以用來產生偽隨機數 (pseudo-random numbers),產生方式其實是用某種公式算出來的,至於為什麼不使用真隨機產生,可以參考這篇

random module 不適合使用在安全性或加密用途
如果有此需求可以使用 secrets module

下面會針對隨機產生數字、隨機抽取出元素列出一些常用的方法

指定範圍內隨機產生一個整數

1. randrange(start, stop, step)

如果 start > stop 會發生 ValueError;回傳值範圍為 start <= 回傳值 < stop

參數 敘述 預設值
start 指定隨機數範圍起點,選填。 0
stop 指定隨機數範圍終點,必填。 n/a
step 指定隨機抽取的間隔,選填。 1
import random    # 務必要先引入
print(random.randrange(0, 5, 2))   # 可能出現 0, 2, 4 其ㄧ
print(random.randrange(1, 5))      # 可能出現 1, 2, 3, 4 其ㄧ
print(random.randrange(5))         # 可能出現 0, 1, 2, 3, 4 其ㄧ

2. randint(a, b)

如果 a > b 會發生 ValueError,回傳值範圍為 a <= 回傳值 <= b ,有沒有覺得跟 randrange 很雷同,其實 randint 就是 randrange(a, b + 1) 的另一種寫法。

import random    # 務必要先引入
print(random.randint(1, 5)     # 可能出現 1, 2, 3, 4, 5 其ㄧ
print(random.randrange(1, 6)   # 可能出現 1, 2, 3, 4, 5 其ㄧ

隨機產生一個浮點數

1. random()

會產生一個 0.0 ~ 1.0 之間的任一浮點數。

import random    # 務必要先引入
print(random.random())   # 0.9016921451498453

2. uniform(a, b)

回傳值範圍為 a <= 回傳值 <= b

import random    # 務必要先引入
print(random.uniform(10, 50))   # 49.98014509364687

從序列隨機抽取

序列是元素的集合,如: stringListTuple 等,可針對序列做隨機相關的方法,這讓我想到以前數學課 C 幾取幾的東東。

1. choice(seq) 多選一

從序列中隨機取得一個元素,seq 為空會產生 IndexError

import random    # 務必要先引入
print(random.choice(["一", "二", "三"]))   # "二"

2. choices(population, k=n) 取後放回

從序列中隨機抽取 n 個元素,可重複抽取,會回傳 List,population 為空會產生 IndexError;另有參數可以配置權重,提高選中機率,細節可參見最後的參考資料。

import random    # 務必要先引入
print(random.choices(["一", "二", "三", "四"], k=3))   # ["一", "三", "一"]

3. sample(population, k=n) 取後不放回

從序列中隨機抽取 n 個元素,不重複抽取,會回傳 List,如果 n > len(population) (樣本數 > 母體數) 會產生 ValueError;有其他參數可提高選中機率,細節可參見最後的參考資料。

import random    # 務必要先引入
print(random.sample(["一", "二", "三", "四"], k=3))   # ["一", "三", "四"]

4. shuffle(x) 隨機排序

將傳入的 list 原地 (in place) 打亂排序;若想保留原本的陣列,回傳一個新的打亂後 list,可以使用 sample(x, k=len(x))

import random    # 務必要先引入

my_list = ["一", "二", "三", "四"]

# shuffle 將傳入陣列原地隨機排序
random.shuffle(my_list)
print(my_list)   # ["一", "三", "四", "二"]

# shuffle 不會回傳值
new_list = random.shuffle(my_list)
print(new_list)   # None

# sample 可以回傳一個打亂後的新 list
ori_list = ["一", "二", "三", "四"]
new_list = random.sample(ori_list, k=len(ori_list))
print(ori_list)    #  ["一", "二", "三", "四"]
print(new_list)    #  ["三", "四", "二", "一"]

隨機結果再現

這部分我覺得有點難以想像,所以就舉 RPG 的例子來幫助理解。

1. seed(a) 指定章節開始

可以初始化亂數產生器,a 預設值為 None ,a = None 時會自動帶入當前的系統時間,可以指定 a 來獲得一樣的亂數值。

import random    # 務必要先引入
# case A
random.seed(10)
print(random.random())   # 0.5714025946899135
print(random.random())   # 0.4288890546751146

# case B
random.seed(100)
print(random.random())    # 0.1456692551041303

# case C: 將 seed 設回 10,會得到跟 case A 一樣的結果
random.seed(10)
print(random.random())   # 0.5714025946899135
print(random.random())   # 0.4288890546751146

2. getstate()、setstate(state_obj) 接續進度

getstate() 存檔功能

會回傳一個產生器當前狀態的物件;如要恢復當初的狀態,要將物件傳遞給 setstate()

setstate(state_obj) 讀檔功能

傳入從 getstate() 得到的物件,可以恢復產生器在調用 getstate() 時的狀態。

import random    # 務必要先引入

# 不初始化也可以透過 getstate、setstate 來獲得一致結果
# 只是產生的隨機數基本上會跟下面例子不一樣
random.seed(10)

# 將目前產生器狀態存檔
state = random.getstate()
print(random.random())   # 0.5714025946899135
print(random.random())   # 0.4288890546751146

# 讀檔以重現存檔時的狀態
random.setstate(state)
print(random.random())   # 0.5714025946899135
print(random.random())   # 0.4288890546751146

參考資料


#Python







Related Posts

《寫給所有人的運算思維入門》- 寫程式到底是在幹嘛?

《寫給所有人的運算思維入門》- 寫程式到底是在幹嘛?

進階 React Component Patterns 筆記(上)

進階 React Component Patterns 筆記(上)

2356. Number of Unique Subjects Taught by Each Teacher

2356. Number of Unique Subjects Taught by Each Teacher


Comments