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}')
목록 삭게로! 맨위로
번호 제목 이름 날짜 조회
167945 [질문] 스키장 숙소가 깨끗한 곳, 새로 지은 곳 어디있을까요? [6] LG의심장박용택10904 22/12/20 10904
167943 [질문] 현재 제주 특파원 계신가요? [11] 핸드레이크9903 22/12/20 9903
167942 [질문] 2004년 이후로 한정하면 메시-호날두 다음번 선수들은.. [8] 마르키아르8797 22/12/20 8797
167941 [질문] 외국은 인구에 비해 일자리가 풍부한 이유가 있는지요...? [10] nexon9485 22/12/20 9485
167940 [질문] 아바타2, 정녕 어느 상영관에서 봐야 합니까? [15] 택배11462 22/12/20 11462
167939 [질문] 삼탠바이미 사용중이신분, 어떤거치대 사용하시나요? [1] 티라노9310 22/12/20 9310
167938 [질문] 예전에 봤던 스타 관련 만화인데요 [2] 데비루쥐9704 22/12/20 9704
167937 [질문] 2살,4살 조카 크리스마스 선물 추천 부탁드려요. [10] 계란후라이7505 22/12/20 7505
167936 [질문] 대충 크리스마스 이브 데이트코스 질문 [10] middle standing8039 22/12/20 8039
167935 [질문] 왼쪽 등 통증이 심합니다. [19] 귀여운호랑이8395 22/12/20 8395
167930 [질문] 축구 클럽팀 PSG가 챔스 우승을 못하는 이유가 있나요? [21] 니하트11775 22/12/20 11775
167929 [질문] 전장연 시위 막을 수 있는 방법은 없는건가요?? [9] 하늘운동8492 22/12/20 8492
167928 [질문] 아이폰의 TrueDepth 카메라 기술에 대한 질문입니다! [8] 나혼자만레벨업10492 22/12/20 10492
167927 [질문] 피씨 견적 질문 [16] 정답 유형11649 22/12/20 11649
167926 [질문] 근육이완제의 효과가 갑자기 궁금합니다. [4] BISANG11775 22/12/20 11775
167924 [질문] 벤트없는 코트 불편한가요? [2] 어센틱10187 22/12/20 10187
167923 [질문] 컴퓨터 사양 문의합니다. [9] 엉망저그9181 22/12/20 9181
167922 [질문] 삼성페이 결제취소 질문 하나만 할게요! [22] 지나가는행인!11417 22/12/19 11417
167921 [질문] 현재 청약 신청하는 건 말리시는 입장이실까요? [33] kafka13323 22/12/19 13323
167920 [질문] 이중창 샤시 결로 방지용 제품 [6] 인생은서른부터9174 22/12/19 9174
167919 [질문] 오버워치2 용 게임용 모니터 추천 부탁드립니다. [9] cherish11708 22/12/19 11708
167917 [질문] 페널티킥은 파울당한 선수가 차는게 맞는거 아닌가요? [35] 목캔디9690 22/12/19 9690
167916 [질문] 40대에 공공기관 무기계약직(행정,사무) 갈만 할까요. [7] 젤렌스키8971 22/12/19 8971
목록 이전 다음
댓글

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