Monty Hall Problem 파이썬으로 증명하기

Monty Hall Problem

  • 몬티 홀이라는 게임 쇼에서 유래한 확률문제
  • 당신이 선택할 세 개의 문 중 두 개에는 염소가, 하나에는 스포츠카가 기다리고 있다. 내가 문을 고르면 사회자는 나머지 두개 문 중에서 염소가 있는 문을 열어준다. 그 때 내가 기존에 골랐던 문을 고수하는 것과, 나머지 한 개의 문으로 갈아타는 것 중 어느 것이 스포츠카에 더욱 가까운 선택인지 증명하는 문제이다.

증명 (ulgoon 선생님의 해설)

  • 랜덤 선택을 100번 또는 1000번의 반복하면서, 내 선택을 고수하는 것(Stay)과 바꾸는 것(Switch) 각각의 스포츠카 당첨 횟수를 구한다.

Pseudocoding

  1. 두 개의 염소와 하나의 스포츠카를 갖는 리스트 doors를 만든다.
  2. 리스트 안에서 랜덤으로 나의 선택 하나를 고른다.
  3. 나머지 두 요소 중 염소를 리스트에서 뺀다.
  4. 나의 선택이 스포츠카인 경우와 리스트에 남아있는 문이 스포츠카인 경우를 세서 비교한다.

Coding

  • for문을 이용하여 100번 실행하면서 stay와 switch의 경우의 수를 구해보았다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import random


stay = 0 #stay와 switch의 결과값 비교를 위한 initialize
switch = 0

for _ in range(100): #반복할 횟수는 일단 100으로.
doors = [0, 0, 1] #편의상 0은 염소, 1은 스포츠카로.
random.shuffle(doors) #doors 리스트 내의 요소들을 마구 섞어주기
user_choice = doors.pop() #나의 선택과 동시에 doors에서는 해당 요소 제거
doors.remove(0) #doors에 남은 요소 중 염소(0)를 제거
if user_choice == 1:
stay += 1 #처음 선택에 머물렀을 때 스포츠카를 탄 것이므로 stay 경우의 수를 1 더해주기
else:
switch += 1 #선택을 바꾸었어야 하므로 switch의 경우의 수를 1 더해준다.
  • 실행횟수를 사용자화하기 위해 trial = int(input())으로 인풋을 받고 for문의 range(100) 대신 range(trial)을 넣어주어도 된다.

결과

  • 처음 실행에는 100번 중 stay 30, switch 70이 나왔다.
  • 실행횟수를 늘리면서 stay/trial*100, switch/trial*100을 출력해보면 33.33%와 66.67%에 수렴한다.

느낀 점

처음에는 그냥 셋 중 하나는 33.33%이고 둘 중 하나는 50%인거 아니야? 라고 단순히 생각했는데, 코드로 보니 이유를 명확하게 파악할 수 있다. doors.remove(0)가 없어도 저 코드는 동일하게 작용한다. 즉 처음부터 switch는 3개 중 2개의 기회를 혼자 가지고 있는 것이다.

도대체 이걸 어떻게 증명하란 건지 머리가 뽀개지는 줄 알았다. 비록 스스로 증명하는 것에 실패하는 바람에 ulgoon선생님의 해설에 의존했고, 내가 끼적였던 코딩은 공유하기도 부끄러울 정도로 엉망진창이긴 하지만 머리가 뽀개질 정도로 고민해보지 않았다면 이 해설이 이토록 명쾌하게 설명한다는 희열은 느끼지 못했을 것이다.

인생에서도 Monty Hall에서 고민하는 상황이 많이 벌어진다. 내가 선택한 길이지만 바꿔야 하나 고민될 때, 또는 내 선택에 영향을 주는 사실이 발견될 때 등. 그러나 Monty Hall Problem은 확률 게임일 뿐이다. 인생은 단순한 확률게임관 비교할 수도 없을 만큼 많은 데이터와 경험이 영향을 미친다. 포장도로도 갖춰지지 않은 정글이라면 스포츠카보다 염소를 타는 게 더 마음편할 수 있으니 나의 선택도, 결과도 너무 낙심하지 말자는 이상한 교훈으로 마무리.