PGR21.com
- PGR21 관련된 질문 및 건의는 [건의 게시판]을 이용바랍니다.
- (2013년 3월 이전) 오래된 질문글은 [이전 질문 게시판]에 있습니다.
통합 규정을 준수해 주십시오. (2015.12.25.)
Date 2022/12/16 12:11:21
Name NSpire CX II
Subject [질문] 파이썬으로 몬티홀 문제 시뮬레이션 해보고 있는데 조언 부탁드립니다 (수정됨)
할 일도 없고 해서 월급루팡짓 하다가 파이썬으로 몬티홀 문제를 시뮬레이션 해보려고 하는데 아무리 돌려도 확률이 1/2에 수렴하네요

무작위로 차가 있는 문과 플레이어의 선택을 할당하고, 그 이후 사회자가 플레이어가 고르지 않은 문 중 양이 있는 문을 고르도록 코딩을 했습니다. 제 생각에는 정말 아무 문제 없는 코드인데 확률이 왜 그리 나오는지 모르겠네요.

만일 플레이어가 1번 문을 골랐는데 1번 문이 실제로 정답이었다면 사회자는 2번이나 3번 문 중에서 아무 거나 열어줄 것이고, 1번 문을 골랐는데 2번 문이 정답이었다면 정답과 플레이어의 선택 모두 피해서 3번 문만 열어줄 것이라는 것이 핵심 같은데.. 도당체 왜 작동을 안 하는지.

코드는 아래에 올렸습니다. 영어 문법 오류나 지저분한 코드는 좀 봐주십시오 흐흐

import random

iteration = 1000
win = 0
# Times that the player has chosen each door
a = b = c = 0
# Times that each door was with a car
acar = bcar = ccar = 0

for i in range(0, iteration):
    open_door = ""
    choice = ""
    car = ""
    random_value = random.random()
    second_random_value = random.random()
    third_random_value = random.random()
    fourth_random_value = random.random()

    # assigning the door with the car

    if random_value < 1/3:
        car = "a"
    elif 1/3 < random_value < 2/3:
        car = "b"
    else:
        car = "c"

    # player makes an arbitrary decision

    if fourth_random_value < 1/3:
        choice = "a"
    elif 1/3 < fourth_random_value < 2/3:
        choice = "b"
    else:
        choice = "c"

    # Now Monty opens a door with a sheep that the player did not pick

    if car == "a":
        if choice == "a":
            if second_random_value < 1/2:
                open_door = "b"
            else:
                open_door = "c"

        if choice == "b":
            open_door = "c"

        if choice == "c":
            open_door = "b"

    if car == "b":
        if choice == "a":
            open_door = "c"

        if choice == "b":
            if second_random_value < 1/2:
                open_door = "a"
            else:
                open_door = "c"

        if choice == "c":
            open_door = "a"

    if car == "c":
        if choice == "a":
            open_door = "b"

        if choice == "b":
            open_door = "a"

        if choice == "c":
            if second_random_value < 1/2:
                open_door = "a"
            else:
                open_door = "b"

#  and then the player changes decision

    if open_door == "a":
        if third_random_value < 1/2:
            choice = "b"
        else:
            choice = "c"

    if open_door == "b":
        if third_random_value < 1/2:
            choice = "a"
        else:
            choice = "c"

    if open_door == "c":
        if third_random_value < 1/2:
            choice = "a"
        else:
            choice = "b"

    if choice == car:
        win += 1

    # for debugging

    if choice == "a":
        a += 1
    elif choice == "b":
        b += 1
    else:
        c += 1

    if car == "a":
        acar += 1
    elif car == "b":
        bcar += 1
    else:
        ccar += 1

    # for debugging

print("The", iteration, "times simulated probability of winning is", win/iteration)
print("The player picked a, b, c for each of", a, b, c, "times")
print("The actual cases for a,b,c doors were ", acar, bcar, ccar, "times")











통합규정 1.3 이용안내 인용

"Pgr은 '명문화된 삭제규정'이 반드시 필요하지 않은 분을 환영합니다.
법 없이도 사는 사람, 남에게 상처를 주지 않으면서 같이 이야기 나눌 수 있는 분이면 좋겠습니다."
마술사
22/12/16 12:23
수정 아이콘
사회자가 보여준뒤 바꾸면 1/2가 되는게 맞으니까 그렇습니다
NSpire CX II
22/12/16 12:29
수정 아이콘
2/3이 되는 걸로 알고 있어서요..
NSpire CX II
22/12/16 12:25
수정 아이콘
아 자문자답입니다.

문제를 잘못 이해했습니다. 1번을 고른 상태에서 3번 문이 꽝임을 보여준 후에, 플레이어가 1번과 2번 중 아무거나 고르는 것이 아니라 무조건 2번으로 가야 하는 건데 전자로 이해해서 잘못 나온 거 같네요.
NSpire CX II
22/12/16 12:30
수정 아이콘
이런. 사회자가 문을 보여준 이후로 선택을 강제로 바꾸게 만들어도 여전히 1/2가 나오네요. 뭐가 문제야!

import random

iteration = 100000
win = 0
# Times that the player has chosen each door
a = b = c = 0
# Times that each door was with a car
acar = bcar = ccar = 0

for i in range(0, iteration):
open_door = ""
choice = ""
car = ""
random_value = random.random()
second_random_value = random.random()
third_random_value = random.random()
fourth_random_value = random.random()

# assigning the door with the car

if random_value < 1/3:
car = "a"
elif 1/3 < random_value < 2/3:
car = "b"
else:
car = "c"

# player makes an arbitrary decision

if fourth_random_value < 1/3:
choice = "a"
elif 1/3 < fourth_random_value < 2/3:
choice = "b"
else:
choice = "c"

# Now Monty opens a door with a sheep that the player did not pick

if car == "a":
if choice == "a":
if second_random_value < 1/2:
open_door = "b"
else:
open_door = "c"

if choice == "b":
open_door = "c"

if choice == "c":
open_door = "b"

if car == "b":
if choice == "a":
open_door = "c"

if choice == "b":
if second_random_value < 1/2:
open_door = "a"
else:
open_door = "c"

if choice == "c":
open_door = "a"

if car == "c":
if choice == "a":
open_door = "b"

if choice == "b":
open_door = "a"

if choice == "c":
if second_random_value < 1/2:
open_door = "a"
else:
open_door = "b"

# and then the player changes decision

if open_door == "a":
if choice == "b":
choice = "c"
if choice == "c":
choice = "b"

elif open_door == "b":
if choice == "a":
choice = "c"
if choice == "c":
choice = "a"

elif open_door == "c":
if choice == "a":
choice = "b"
if choice == "b":
choice = "a"

if choice == car:
win += 1

# for debugging

if choice == "a":
a += 1
elif choice == "b":
b += 1
else:
c += 1

if car == "a":
acar += 1
elif car == "b":
bcar += 1
else:
ccar += 1

# for debugging

print("The", iteration, "times simulated probability of winning is", win/iteration)
print("The player picked a, b, c for each of", a, b, c, "times")
print("The actual cases for a,b,c doors were ", acar, bcar, ccar, "times")
jjohny=쿠마
22/12/16 12:31
수정 아이콘
네. 사회자가 정답 아닌 문을 하나 열어서 [정답 후보 문이 2개 남은 상태에서]
플레이어가 랜덤하게 둘 중 하나를 고르면 확률은 50%가 나오는 게 자연스럽습니다.

그런데 코드를 바꿔도 1/2가 나온다니... 흥미롭군요.
NSpire CX II
22/12/16 12:32
수정 아이콘
강제로 바꾸게 만들어도 1/2가 나온다니 으으
공실이
22/12/16 12:31
수정 아이콘
중간에 바꿀때 선택을 랜덤으로 바꾸면 5대5가 나오는게 맞는것 같습니다. 첫번째 초이스와 두번째 초이스가 같은건지 다른건지 구분하는 코드가 있어야 한다고 적고 있었는데

이미 자문자답 하셨군요 하핫
NSpire CX II
22/12/16 12:33
수정 아이콘
네 첫번째 초이스를 기반으로 사회자가 여는 문을 고르고, 그 이후에 선택을 강제로 바꾸게 만들어도 1/2가 나오네요 ㅠㅠ
jjohny=쿠마
22/12/16 12:33
수정 아이콘
제가 최근에 엑셀로 몬티홀 문제에서 발생 가능한 케이스들 및 그 비율을 비교해서 만든 게 있는데 혹시 참고가 되실지 모르겠습니다.
-----------------------------------------------------------------------------------------
- 사회자가 정답을 아는 경우(원래의 몬티홀 문제)에 각각의 케이스들 및 그 비율을 시각화해보았습니다.
자동차(정답) 위치 기준: https://imgur.com/lCuue4g
최초 선택 위치 기준: https://imgur.com/ssfdvGF

위 이미지들을 참조하면, 사회자가 정답을 아는 경우에는,
[참가자가 최초 선택한 문이 정답일 경우], 사회자는 두 가지 선택지를 가집니다.
[참가자가 최초 선택한 문이 정답이 아닐 경우], 사회자는 한 가지 선택지만을 가집니다.
이 차이가 전체 확률 계산에서 중요한 차이를 가져옵니다.

-------------------------------

한편, 사회자가 정답을 모르는 경우, 각각의 케이스들 및 그 비율을 시각화해보면 아래와 같이 할 수 있을 것 같습니다.
자동차(정답) 위치 기준: https://imgur.com/KJXvZmB
최초 선택 위치 기준: https://imgur.com/P6mRg28
(모르는 경우에 대해서는 깊게 생각해본 적이 없어서 정확하지 않을 수 있습니다
NSpire CX II
22/12/16 12:34
수정 아이콘
네 그 부분은 고려를 해놓았습니다. 본문에서도 적었지만 플레이어가 처음에 정답을 맞췄을 때는 사회자의 선택지가 2개지만, 플레이어가 틀렸을 경우 사회자의 선택지는 하나만 남게 되지요.
구운아몬드
22/12/16 12:33
수정 아이콘
# and then the player changes decision


if choice == "a":
if open_door == "b":
choice = "c"
if open_door == "c":
choice = "b"

elif choice == "b":
if open_door == "a":
choice = "c"
if open_door == "c":
choice = "a"

elif choice == "c":
if open_door == "a":
choice = "b"
if open_door == "b":
choice = "a"

이렇게 하니까 나오네요
NSpire CX II
22/12/16 12:38
수정 아이콘
조언 감사합니다 드디어 해결했어요 흑흑
공실이
22/12/16 12:35
수정 아이콘
if choice == "b":
choice = "c"
if choice == "c":
choice = "b"

요 부분에 버그가 있네요. choice를 c로 바꾼담에 아래 if에서 한번 더걸려서다시 b로 바뀝니다.

# and then the player changes decision
if open_door == "a" and choice == 'b':
choice = "c"
elif open_door == "a" and choice == 'c':
choice = "b"
elif open_door == "b" and choice == 'c':
choice = "a"
elif open_door == "b" and choice == 'a':
choice = "c"
elif open_door == "c" and choice == 'b':
choice = "a"
elif open_door == "c" and choice == 'a':
choice = "b"

요렇게 하시면 2/3 나옵니다.
NSpire CX II
22/12/16 12:36
수정 아이콘
아 이거 코드 진짜 깔끔하네요 고수의 향기가 느껴집니다
NSpire CX II
22/12/16 12:38
수정 아이콘
아!!!!!!!!!! 이거네요!!!!!!!!!

if choice == "b":
choice = "c"
elif choice == "c":
choice = "b"

로 바꿔주니까 문제가 사라졌습니다! 감사합니다 진짜로! 앓던 체증이 싹 내려가네요!!!
NSpire CX II
22/12/16 12:39
수정 아이콘
와 그냥 if문 써도 되겠지 싶었는데 elif 안 쓰고 그냥 if로 도배한 게 문제였군요. 와 이걸 어떻게 알아보셨는지 구세주시여 ㅠㅠㅠ
공실이
22/12/16 12:53
수정 아이콘
이렇게 좋아해주시니 제가 다 기분이 좋네요 흐흐
NSpire CX II
22/12/16 12:55
수정 아이콘
어제부터 "아니 이렇게 완벽한 코드가 왜 안 돌아가는 거야!"하고 골머리를 싸맸는데 그게 해결되니까 쾌감이 장난 아니네요 흐흐
공실이
22/12/16 13:08
수정 아이콘
(수정됨) 크크 맞습니다. 그 뽕맛때문에 프로그래머 됐습니다...

어느 연구에서 봤는데 함수 하나가 7줄 넘어가면 버그가 한개 이상 있다고 합니다. 1, 한 함수 사이즈를 작게 여러개로 쪼개기 2. 들여쓰기 단계 적게 가져가기
요 두가지는 항상 맞는건 아니지만 버릇을 들이면 코드 가독성이 많이 개선됩니다.
NSpire CX II
22/12/16 17:28
수정 아이콘
가급적 간결한 블록으로 나누는 게 좋은 거군요 꿀팁 감사합니다!
jjohny=쿠마
22/12/16 12:38
수정 아이콘
메데타시 메데타시
뿌루빵
22/12/16 13:39
수정 아이콘
import random

iteration = 1000
cwin = 0 # 바꿨을때 이기는 수
dcwin = 0 # 안바꿨을때 이기는 수
# Times that the player has chosen each door
# Times that each door was with a car
answer = 0
li = []

for i in range(1,4):
li.append(i)

for i in range(0, iteration):
non_answer = li[:]
answer = random.randrange(1,4)
pchoice = random.randrange(1,4)
non_answer.remove(answer)
if pchoice != answer :
non_answer.remove(pchoice)

open = random.choice(non_answer)
print(f" 정답은 {answer} 고른건 {pchoice} 사회자가 open 한건 {open}")
if answer != pchoice:
cwin+=1
else:
dcwin+=1

print(cwin)
print(dcwin)

if 문을 조금 줄여봤습니다.
NSpire CX II
22/12/16 17:28
수정 아이콘
헣헣 배열도 쓰시고 if문도 거의 안 쓰시고 대단하시네요..
Rorschach
22/12/16 14:54
수정 아이콘
심심풀이로 하시는 듯 한데, 이런 선택지 같은 것들은 문자로 하는 것 보다는 숫자로 하는 것이 활용도가 훨씬 쉽습니다.

일단 문 세 개를 0,1,2로 하고, 자동차가 있는 문을 셋 중에 하나 랜덤으로, 그리고 첫 선택지도 랜덤으로 둡니다.
그리고 사회자가 여는 문을,
(1) 첫 선택이 자동차였을 경우 남은 문 둘 중에 하나로 선택해야 하죠. 이 때 그냥 1,2 중 랜덤으로 하나를 고르고, 첫 선택에 더해주면 됩니다. 다만 첫 선택이 1이었을 때 랜덤으로 2가 나오거나, 첫 선택이 2라면 사회자가 여는 문이 3이상이 되어버리므로, % 연산자로 나머지만 남기면 됩니다.
(2) 반대로 첫 선택이 자동차가 아니었을 경우 그냥 남은 문이 되는데, 0,1,2로 설정할 경우 총 합이 3이 되니 3에서 자동차가 있는 문 번호, 첫 선택한 번호를 차례로 빼주면 남은 문이 됩니다. (ex 0번에 차가 있고 첫 선택이 2번일 경우, 3-0-2=1)

이러면 전체 줄 수를 매우 컴팩트하게 줄일 수 있어요.

####################################################
import random

num = 100000
keep = 0
change = 0

for i in range(num):
car = random.randrange(3)
choice = random.randrange(3)

if car==choice:
a = random.randrange(2)
opendoor = (choice + a + 1 )%3
else:
opendoor = 3-choice-car

if choice==car: keep+=1
if 3-choice-opendoor==car: change+=1

print(keep/num, change/num)
####################################################
NSpire CX II
22/12/16 17:27
수정 아이콘
와 이게 고수의 압축 능력이군요..
고양이손
22/12/17 12:38
수정 아이콘
car = choice(unselected_doors)
first_choice = select_a_door(unselected_doors)

car는 unselected_doors 중에서 랜덤 선택 후 unselected_doors는 그대로 두고,
first_choice는 unselected_doors 중에서 랜덤 선택 후 unselected_doors에서 제외합니다.
----
from random import choice

doors = 10
opens = 8
total = 100000
keep, change = 0, 0
debug = False

def select_a_door(unselected_doors):
selected_door = choice(unselected_doors)
unselected_doors.remove(selected_door)
return selected_door

def open_doors_by_host(unselected_doors, car):
open_doors = []
is_car_unselected = car in unselected_doors
if is_car_unselected: unselected_doors.remove(car)
for i in range(opens): open_doors.append(select_a_door(unselected_doors))
if is_car_unselected: unselected_doors.append(car)
return open_doors

for i in range(total):
unselected_doors = list(range(doors))
car = choice(unselected_doors)
first_choice = select_a_door(unselected_doors)
open_doors = open_doors_by_host(unselected_doors, car)
changed_choice = select_a_door(unselected_doors)

if debug: print(f'car: {car}, first_choice: {first_choice}, open_doors: {open_doors} changed_choice: {changed_choice}')

if car == first_choice: keep += 1
elif car == changed_choice: change += 1

# endfor

print(f'keep: {keep / total}, change: {change / total}')
목록 삭게로! 맨위로
번호 제목 이름 날짜 조회
167865 [질문] 파이썬 코드 질문입니다. 죄송해요 [2] 월터화이트6545 22/12/16 6545
167864 [질문] 겨울철 등산아우터 범용성 높은 제품으로 추천부탁드립니다. [5] 이민들레7282 22/12/16 7282
167863 [질문] 부산여행관련 질문입니다.. [12] Kubernetes8900 22/12/16 8900
167862 [삭제예정] 와이프가 바람을 폈습니다 [37] 삭제됨12649 22/12/16 12649
167861 [질문] 한글 덮어쓰기 복구 방법 없나요? [3] 아이시스 8.010723 22/12/16 10723
167860 [삭제예정] 전세 묵시적 계약갱신의 횟수 관련 [2] 삭제됨6764 22/12/16 6764
167859 [질문] fm2023 갓겜입니까?? [11] kogang20019957 22/12/16 9957
167858 [질문] 돈들여서 영어 회화 배우기 좋은 방법은 뭐가 있을까요? [11] 알렉스터너10169 22/12/16 10169
167857 [질문] 앱스토어/구글플레이에 올라온 콘솔게임 정리해놓은 사이트가 있을까요? 고오스7500 22/12/16 7500
167856 [질문] 파이썬으로 몬티홀 문제 시뮬레이션 해보고 있는데 조언 부탁드립니다 [26] NSpire CX II9650 22/12/16 9650
167855 [질문] PC에서 쓸만한 게임 패드 추천 부탁 드립니다 [14] 대출 30년10648 22/12/16 10648
167854 [질문] 영어 쉐도잉을 하기에 적합한 외국 드라마나 애니메이션은 어떤 것이 좋을지요..? [8] nexon9373 22/12/16 9373
167853 [질문] [게임] 위처 1, 2 스토리는 어떻게 알면 좋을까요? [10] 류지나10493 22/12/15 10493
167852 [질문] 아르헨티나 vs 프랑스 .. 어디 응원하시나요? [52] 마르키아르8883 22/12/15 8883
167851 [질문] 쇼파 배드를 구입할까 하는데 물건 고르는 팁좀 주실 수 있을까요? [10] Beyond9343 22/12/15 9343
167850 [질문] 노래를 찾습니다 [3] 형리7352 22/12/15 7352
167849 [질문] 맥 리얼포스 블루투스 연결 불가 문제 질문입니다. [1] 7649 22/12/15 7649
167848 [질문] 아버지께서 핸드폰 매장에서 당하신것 같습니다. [9] 사다드9597 22/12/15 9597
167847 [질문] 아바타2 일반관2d로 관람해도 괜찮나요? [6] 한이연6907 22/12/15 6907
167845 [질문] 혼자서 볼링 점수 올릴 수 있을까요? [18] 탄야8860 22/12/15 8860
167844 [질문] 30대 중반 15000원 짜리 재밌는 선물이 뭐있을까요? [33] 안녕!곤9712 22/12/15 9712
167843 [질문] 자유게시판 사진 첨부 방법 [6] 김승구8678 22/12/15 8678
167842 [삭제예정] 모든 답변들 감사합니다! [80] 삭제됨10442 22/12/15 10442
목록 이전 다음
댓글

+ : 최근 1시간내에 달린 댓글
+ : 최근 2시간내에 달린 댓글
맨 위로