0

random — Pseudorandom Number Generators (Part I)

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ị minmax 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ì minmax phải thỏa mãn điều kiện min < maxmin, 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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí