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}')
목록 삭게로! 맨위로
번호 제목 이름 날짜 조회
167875 [질문] 혹시 선릉역 주변에 콜키지비 받고 술 가져갈수 있는 곳 있나요? [5] 세인트루이스8735 22/12/17 8735
167874 [질문] VMWARE 구동 시 E코어만 디립다 돌리는 문제.. [5] 교대가즈아8446 22/12/17 8446
167873 [질문] 위스키 서울에서 살만한데가 어디 있을까요? [8] lefteye8469 22/12/17 8469
167872 [질문] 이적료 주고 아이돌 그룹 만들수 있으면? [16] 오타니7125 22/12/17 7125
167871 [질문] 위쳐3(ps4pro) 버그 질문있습니다. 스카야7145 22/12/17 7145
167870 [질문] 미국계정 PS5 에서 한국어 위쳐 3 하는 방법 질문 [6] vitaminwater7914 22/12/17 7914
167869 [질문] 스팀과 플레이스토어 관련 혜택있는 신용카드 있을까요? [2] Winter_SkaDi6259 22/12/17 6259
167868 [질문] DB 설계 연습중인데 뇌정지가 와서 질문드립니다 [9] 오렌지 태양 아래6781 22/12/17 6781
167867 [질문] 부산 여행 접대 코스? 추천 좀 부탁 드려요. (스타벅스 1만원). [13] 실버벨11319 22/12/17 11319
167866 [질문] 생활의고수 피잘러님들 난방비 절약 꿀팁 부탁드립니다. [7] Liberal7049 22/12/17 7049
167865 [질문] 파이썬 코드 질문입니다. 죄송해요 [2] 월터화이트6446 22/12/16 6446
167864 [질문] 겨울철 등산아우터 범용성 높은 제품으로 추천부탁드립니다. [5] 이민들레7115 22/12/16 7115
167863 [질문] 부산여행관련 질문입니다.. [12] Kubernetes8797 22/12/16 8797
167862 [삭제예정] 와이프가 바람을 폈습니다 [37] 삭제됨12472 22/12/16 12472
167861 [질문] 한글 덮어쓰기 복구 방법 없나요? [3] 아이시스 8.010521 22/12/16 10521
167860 [삭제예정] 전세 묵시적 계약갱신의 횟수 관련 [2] 삭제됨6608 22/12/16 6608
167859 [질문] fm2023 갓겜입니까?? [11] kogang20019793 22/12/16 9793
167858 [질문] 돈들여서 영어 회화 배우기 좋은 방법은 뭐가 있을까요? [11] 알렉스터너9936 22/12/16 9936
167857 [질문] 앱스토어/구글플레이에 올라온 콘솔게임 정리해놓은 사이트가 있을까요? 고오스7254 22/12/16 7254
167856 [질문] 파이썬으로 몬티홀 문제 시뮬레이션 해보고 있는데 조언 부탁드립니다 [26] NSpire CX II9503 22/12/16 9503
167855 [질문] PC에서 쓸만한 게임 패드 추천 부탁 드립니다 [14] 대출 30년10467 22/12/16 10467
167854 [질문] 영어 쉐도잉을 하기에 적합한 외국 드라마나 애니메이션은 어떤 것이 좋을지요..? [8] nexon9117 22/12/16 9117
167853 [질문] [게임] 위처 1, 2 스토리는 어떻게 알면 좋을까요? [10] 류지나10202 22/12/15 10202
목록 이전 다음
댓글

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