random — Pseudorandom Number Generators (Part I)
Bài đăng này đã không được cập nhật trong 8 năm
Purpose: Implement một vài hàm sinh số ngẫu nhiên
Avalable In: Python 1.4 trở lên
Module random
cung cấp một bộ sinh số ngẫu nhiên (PRNG - pseudorandom number generator) dựa vào giải thuật Mersenne Twister. Ban đầu được phát triển để sinh ra input cho các mô phỏng Monte Carlo, Mersenne Twister sinh số theo phân phối gần đều (nearly uniform distribution) với period lớn (nếu muốn biết period là gì thì các bạn có thể search Google với từ khóa "The period of a PRNG" nhé ).
1. Generating Random Numbers
Hàm random()
trả về một số thực dấu phẩy động tiếp theo trong nửa khoảng [0, 1).
import random
for i in xrange(5):
print "%04.3f" % random.random()
Chạy chương trình nhiều lần sẽ sinh ra các chuỗi số ngẫu nhiên khác nhau:
$ python random_random.py
0.182
0.155
0.097
0.175
0.008
$ python random_random.py
0.851
0.607
0.700
0.922
0.496
Để sinh số trong một khoảng xác định, ta sử dụng hàm uniform()
import random
for i in xrange(5):
print "%04.3f" % random.uniform(1, 100)
Truyền giá trị min
và max
vào hàm uniform()
sẽ thiết lập giá trị trả về từ hàm random()
với công thức min + (max - min) * random()
.
$ python random_uniform.py
6.899
14.411
96.792
18.219
63.386
2. Seeding
Mỗi lần hàm random()
được gọi, nó lại sinh ra một giá trị khác và có chu kỳ rất lớn trước khi một giá trị được lặp lại. Điều này rất hữu ích để sinh ra các giá trị duy nhất. Tuy nhiên, đôi khi chúng ta lại cần đến cùng một tập dữ liệu trong các phép thử khác nhau. Có một kỹ thuật, đó là sử dụng một chương trình để tạo các giá ngẫu nhiên và lưu lại chúng để xử lý ở trong một bước độc lập khác. Tuy nhiên việc này không thiết thực khi chúng ta làm việc với lượng dữ liệu lớn. May thay, module random
lại cung cấp hàm seed()
để khởi tạo bộ sinh ngẫu nhiên để nó có thể tạo ra các tập giá trị như mong đợi.
import random
random.seed("hehe")
for i in xrange(5):
print "%04.3f" % random.random()
Giá trị seed sẽ điều khiển giá trị đầu tiên được sinh ra bởi công thức được sử dụng để tạo ra các số giả ngẫu nhiên. Và vì công thức là tất định (tất định là gì thì các bạn search Google với từ khóa "giải thuật tất định" là ra) nên các dãy số ngẫu nhiên sẽ chỉ thay đổi nếu chúng ta thay đổi seed. Tham biến truyền vào hàm seed()
có thể là bất cứ đối tượng có thể băm nào (any hashable object). Nếu bỏ quan tham số hoặc truyền giá trị None
vào, thời gian hiện tại của hệ thống sẽ được sử dụng. Giá trị hệ thống này cũng được sử dụng để khởi tạo bộ sinh khi module được import lúc ban đầu. Nếu các nguồn ngẫu nhiên được cung cấp bởi hệ điều hành, chúng sẽ được sử dụng thay thế cho thời gian hệ thống (xem hàm os.urandom()
để biết thêm chi tiết).
$ python random_seed.py
0.141
0.890
0.022
0.116
0.650
Chạy thử chương trình lần nữa
$ python random_seed.py
0.141
0.890
0.022
0.116
0.650
3. Saving State
Một kỹ thuật hữu ích khác để điều khiển dãy số ngẫu nhiên là lưu trạng thái nội tại của PRNG giữa các phép thử. Hàm getstate()
trả về một object lưu lại trạng thái nội tại của hệ thống và object này có thể được truyền vào hàm setstate()
để khôi phục lại trạng thái của PRNG.
import random
import os
import cPickle as pickle
if os.path.exists("state.dat"):
# Restore the previously saved sate
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()
# 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()
Chạy thử:
$ python random_state.py
No state.dat, seeding
0.134
0.847
0.764
After saving state:
0.255
0.495
0.449
$ python random_state.py
Found state.dat, initializing random module
0.255
0.495
0.449
After saving state:
0.652
0.789
0.094
4. Random Integers
random()
sinh ra các số dấu phẩy động. Chúng ta có thể convert kết quả sang dạng số nguyên. Ngoài ra, để thuận tiện hơn, chúng ta có thể sử dụng trực tiếp hàm randint()
. Giả sử gọi randint(min, max)
thì min
và max
phải thỏa mãn điều kiện min < max
và min
, max
nguyên.
import random
print "[1, 100]:"
for i in xrange(3):
print random.randint(1, 100)
print
print "[-5, 5]:"
for i in xrange(3):
print random.randint(-5, 5)
Kết quả:
$ python random_randint.py
[1, 100]:
3
47
72
[-5, 5]:
4
1
-3
Một hàm khác có chức năng tương tự là randrange()
. Hàm này nhận ba tham số (start, stop, step)
. Trong đó step
là không bắt buộc. Khi không có tham số này, randrange(start, stop)
tương đương với randint(start, stop)
.
Khi có tham số step
, randrange(start, stop, step)
sẽ tương đương với việc chọn ngẫu nhiên một giá trị từ range(start, stop, step)
.
import random
print "randrange without step"
for i in xrange(3):
print random.randrange(0, 101)
print
print "randrange with step"
for i in xrange(3):
print random.randrange(0, 101, 5)
Kết quả:
$ python random_randrange.py
randrange without step
26
39
64
randrange with step
90
75
30
5. Picking Random Items
Module random
cung cấp hàm choice()
để lấy ra ngẫu nhiên một phần từ một non-empty sequence (list, str, tuple).
import random
outcomes = {"heads": 0, "tails": 0}
sides = outcomes.keys()
for i in range(1000000):
outcomes[random.choice(sides)] += 1
print "Heads:", outcomes["heads"]
print "Tails:", outcomes["tails"]
Kết quả:
$ python random_choice.py
Heads: 499963
Tails: 500037
All rights reserved