몬티홀 문제(Monty Hall problem)
몬티홀 문제(Monty Hall problem)
몬티홀 문제는 세계에서 가장 유명한 확률 역설입니다. 퀴즈쇼 사회자인 몬티 홀은 세 개의 문 중 하나의 뒤에 자동차가 있고, 두 개의 문 뒤에는 염소가 있다고 알려줍니다. 이때 참가자가 자동차를 고를 확률은 분명히 1/3이죠. 이때 자비로운 사회자가 문 하나를 선택하면 남아 있는 두 개의 문 중에서 염소가 있는 문 하나를 열어서 보여주고 다른 문을 선택할 기회를 한 번 더 줍니다.
이때 참가자는 문을 바꾸는게 좋은 선택일까요?? 아니면 사회자의 심리전에 불과할까요??
예시 파이썬 코드
다음은 참가자가 선택하지 않은 문 가운데 염소가 있는 문을 무작위로 열어주는 전략을 10만번 시뮬레이션 한 코드입니다.
## 일반 몬티홀 코드
import random
def money_hall_simulate(switch, num_trials):
"""
몬티홀 문제 시뮬레이션 함수
: switch - 참가자가 선택을 바꿀지 여부 (True/False)
: num_trials - 시뮬레이션 횟수
: return - 승리한 횟수
"""
# 승리한 횟수 초기화
win_count = 0
for _ in range(num_trials):
# 문 뒤에 상품이 있는 위치와 참가자의 선택을 무작위로 설정 (문은 1~3번이 있음)
prize_door = random.randint(1,3)
player_choice = random.randint(1,3)
# 사회자가 염소가 있는 문을 열어줌(참가자의 선택과 상품의 위치가 같지 않은 문 중 하나를 무작위로 고름
open_door = random.choice([i for i in range(1,4) if i != player_choice and i != prize_door])
# 참가자가 선택을 바꾸기로 한 경우
if switch:
# 참가자는 처음 선택과 사회자가 열어준 문을 제외한 나머지 문을 선택
player_choice = next(i for i in range(1,4) if i != player_choice and i != open_door)
# 최종 선택이 상품이 있는 문이면 승리
if player_choice == prize_door:
win_count += 1
return win_count # 승리 횟수 반환
# 시뮬레이션 실행
num_trials = 100000 # 10만번 시뮬레이션 반복
win_rate_no_switch = money_hall_simulate(False, num_trials) / num_trials # 선택을 바꾸지 않았을 경우 승리 확률
win_rate_switch = money_hall_simulate(True, num_trials) / num_trials # 선택을 바꾸었을 경우 승리 확률
# 결과 출력
print(f"선택을 바꾸지 않았을 때 승리할 확률: {win_rate_no_switch:.2f}")
print(f"선택을 바꾸었을 때 승리할 확률: {win_rate_switch:.2f}")
선택을 바꾸지 않았을 때 승리할 확률: 0.33 선택을 바꾸었을 때 승리할 확률: 0.67
그래프 시각화
시도 순서에 따른 승리 횟수를 시각화 하여 나타내 봅니다.
# ! pip install matplotlib
## 그래프 시각화
import matplotlib.pyplot as plt
# 한글 폰트 지정
plt.rcParams['font.family'] = 'Noto Sans KR'
plt.rcParams['axes.unicode_minus'] = False
# 시뮬레이션 실행 결과 저장 리스트 초기화
win_rates_no_switch = []
win_rates_switch = []
# 시뮬레이션 실행
trial_numbers = range(10, 100001, 100)
for num_trials in trial_numbers:
win_rate_no_switch = money_hall_simulate(False, num_trials) / num_trials
win_rates_no_switch.append(win_rate_no_switch)
win_rate_switch = money_hall_simulate(True, num_trials) / num_trials
win_rates_switch.append(win_rate_switch)
# 결과를 선 그래프로 그리기
plt.figure(figsize=(10, 6))
plt.plot(trial_numbers, win_rates_no_switch, color='#4B0082')
plt.plot(trial_numbers, win_rates_switch, color='#FF1493')
# 10만번 시뮬레이션 한 결괏값을 레이블로 표시
plt.text(70000, 0.36, f"선택을 바꾸지 않았을 때 \n승리 확률:{win_rates_no_switch[-1]:.2f}",
ha='left', va='bottom', color='black', fontweight='bold', fontsize=10)
plt.text(70000, 0.6, f"선택을 바꾸었을 때 \n승리 확률:{win_rates_switch[-1]:.2f}",
ha='left', va='bottom', color='black', fontweight='bold', fontsize=10)
plt.xlabel("시뮬레이션 횟수")
plt.ylabel("승리할 확률")
plt.show()
출처 : 수학은 알고 있다. (김종성_위니버스, 이택호 지음)