Mô phỏng để tìm xác suất

Khi mới bắt đầu làm toán xác suất, đôi khi chúng ta thường đặt ra câu hỏi: “Làm sao có thể kiểm tra lại được kết quả của mình là đúng hay sai?”

…đây là là một câu hỏi thú vị, mang tính xây dựng cao. Với máy tính, bạn có thể tạo ra các số giả ngẫu nhiên (pseudorandom number generator), đồng thời lập trình mô phỏng tình huống, từ đó thực hiện một lượng lớn các phép thử, bạn có thể xấp xĩ được xác suất xảy ra trong thí nghiệm của mình.

Điều này là do ảnh hưởng của luật số lớn (law of large numbers) mà chúng ta sẽ thảo luận ở các phần sau.

Tuy nhiên phương pháp này có vài điểm yếu:

  • Điểm yếu lớn nhất của nó là tốn thời gian chạy mô phỏng, việc này thường không nhanh và đòi hỏi lượng mẫu đủ lớn để độ chính xác cao.

  • Điểm yếu thứ hai, các thuật toán tạo ra số giả ngẫu nhiên đóng vai trò quan trọng. Thực sự điều xảy ra đã đủ tính “ngẫu nhiên” hay chưa?!? Trong một số thí nghiệm mô phỏng cực kì đặc biệt thì người ta cần các số “càng ngẫu nhiên càng tốt”, các bộ giả ngẫu nhiên mặc định của máy tính đôi khi không đảm bảo yêu cầu này. (dành cho các bạn tò mò: bản chất của giả ngẫu nhiên máy tính là gì? Gợi ý: vì sao CPU clock của một máy tính luôn luôn có pin CMOS và hàm giả ngẫu nhiên yêu cầu một seed number)

Bạn có biết: Nhờ luật số lớn mà hoạt động kinh doanh của các casino không phá sản… Trong vài lượt ngắn hạn, kẻ đánh bạc có thể “may mắn” và sinh lời… nhưng về lâu về dài thì phần lợi luôn thuộc về casino!


(Nguồn Wikimedia)

Dưới đây là một bài toán thú vị, mà mình mong muốn bạn thử trả lời và kiểm nghiệm nó lại bằng cách lập trình giả lập.


(Nguồn Wikimedia)

Giả sử bạn đang trong một trò chơi truyền hình, và bạn được chọn một trong 3 cánh cửa: đằng sau một cánh cửa là xe hơi, đằng sau hai cánh cửa còn lại là . Bạn được chọn một cánh cửa, giả sử nó là cánh cửa 1, người tổ chức trò chơi biết tất tần tật đằng sau những cánh cửa là gì, người tổ chức chọn một cánh cửa trong hai cánh cửa còn lại chứa dê và mở nó ra trước mắt khán giả, giả sử đó là cánh cửa thứ 3. Anh ấy hỏi bạn: “Bạn có muốn chuyển sang cánh cửa thứ 2 hay không?”

Liệu việc chọn “chuyển cửa” có lợi thế hơn cho bạn?

Gọi \(A,B,C\) lần lượt là các biến cố cửa thứ \(1,2,3\) có xe hơi. Ban đầu bạn không biết gì về 3 cánh cửa trên nên xác suất có xe đối với bạn là như nhau:

\[\Pr(A) = \Pr(B) = \Pr( C ) = \frac{1}{3} \]

Tuy nhiên sau khi người tổ chức mở cánh cửa thứ ba như đề bài… thì xác suất thay đổi như thế nào?

Liệu xác suất \(\Pr(A)=\Pr(B) = 1 / 2\) hay là một con số khác?

Lời giải

#   _______________________________________________________________________
#  |[] ThetaLogShell                                                 |X]|!"|
#  |"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""|"|
#  | > ThetaLog.com                                                      | |
#  | > ENV: Python 3.6.5                                                 | |
#  | > Monty Hall Problem                                                | |
#  |_____________________________________________________________________|/

# Nạp thư viện cần thiết
import random

def monty_hall_problem(trial=1000):
    """
    Mô phỏng bài toán Monty Hall
    In ra kết quả mô phỏng số lần thắng bởi lựa chọn stay và switch

    :param trial: int - số phép thử mô phỏng
    :return: tuple(stay, switch) - một tuple số lần thắng stay và switch
    """

    # Đếm số lần thắng với việc:
    # - stay: giữ nguyên lựa chọn
    # - switch: chuyển đổi lựa chọn
    stay_wins = 0
    switch_wins = 0

    for i in range(trial):
        action_door = set(range(1,4))
        # Chọn ngẫu nhiên một cửa làm xe nào
        car = random.randint(1, 3)

        # Cánh cửa mà người chơi chọn random vì không biết thông tin gì
        player = random.randint(1, 3)
        action_door.discard(player)

        open_door = None

        while not open_door:
            random_door = random.randint(1, 3)
            if random_door != car and random_door != player:
                open_door = random_door

        action_door.discard(open_door)

        switch = random.sample(action_door, 1)[0]

        if switch == car:
            switch_wins += 1
        else:
            stay_wins += 1

    print("Stay =", stay_wins)
    print("Switch = ", switch_wins)

    return stay_wins, switch_wins


if __name__ == '__main__':
    monty_hall_problem()
#   _______________________________________________________________________
#  |[] ThetaLogShell                                                 |X]|!"|
#  |"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""|"|
#  | > ThetaLog.com                                                      | |
#  | > ENV: R version 3.5.0                                              | |
#  | > Monty Hall Problem                                                | |
#  |_____________________________________________________________________|/

monty.hall.problem <- function(trial=1000){
    # Biến đếm số lần switch thắng và stay thằng
    switch.wins <- 0
    stay.wins <- 0

    # Từ khi R hạn chế vòng for nên chúng ta tạo mảng ngẫu nhiên
    car.door = sample(1:3, trial, replace=TRUE)
    player.door = sample(1:3, trial, replace=TRUE)
    
    # Mô phỏng thí nghiệm
    for (i in 1:trial) {
        open.door <- -1
        switch.door <- -1

        # Mở một cửa không có quà trong 2 cửa
        while (open.door == -1){
            door <- sample(1:3, 1, replace=TRUE)
            if (door != car.door[i] && door != player.door){
                open.door <- door
            }
        }

        # Cửa nếu lựa chọn là switch
        for (door in 1:3){
            if (door != player.door && door != open.door){
                switch.door <- door
            }
        }

        # Đếm xem stay hay switch thắng
        if (switch.door == car.door[i]){
            switch.wins <- switch.wins + 1
        }
        else {
            stay.wins <- stay.wins + 1
        }

    }

    result <- data.frame(stay.wins, switch.wins)

    # trả về kết quả
    return(result)
}
monty.hall.problem()

Tham khảo

  1. Wikipedia contributors. “Law of large numbers.” Wikipedia, The Free Encyclopedia. Wikipedia, The Free Encyclopedia, 25 Jun. 2018. Web. 13 Jul. 2018.

  2. Wikipedia contributors. “Pseudorandom number generator.” Wikipedia, The Free Encyclopedia. Wikipedia, The Free Encyclopedia, 6 May. 2018. Web. 13 Jul. 2018.

  3. Wikipedia contributors. “Monty Hall problem.” Wikipedia, The Free Encyclopedia. Wikipedia, The Free Encyclopedia, 10 Jul. 2018. Web. 13 Jul. 2018.