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}')
목록 삭게로! 맨위로
번호 제목 이름 날짜 조회
170159 [질문] 동사무소에서 불쾌한 일을 겪었는데 제가 예민한건까요? [33] 기다리다9037 23/04/17 9037
170158 [질문] (자동차초보. 테슬라 모델3)수리 방법을 몰라 이웃님께 도움 부탁드립니다 [4] 세바준8169 23/04/17 8169
170157 [질문] PC 견적 질문입니다. [4] soritiger10595 23/04/17 10595
170156 [질문] 공포/경외/무력감이 강렬한 영화 있을까요 [32] 그말싫9167 23/04/17 9167
170155 [질문] 무선충전기 위에 올려두면 뜨거운데 괜찮나요?? [7] CEO9733 23/04/17 9733
170154 [질문] LA에서 1년 간 거주 관련 질문입니다. [4] 입다물어말포이7564 23/04/17 7564
170153 [질문] 하이마트 컴퓨터 질문 [6] up10406 23/04/17 10406
170152 [질문] 외국인 친구들 어디 데려가죠? [24] 어센틱8869 23/04/17 8869
170151 [질문] 카카오택시 경유 싫어하는 이유 있나요? [15] 탄야10812 23/04/17 10812
170150 [질문] 그래픽 카드 당근으로 사려고 하는데 알아둬야할게 있을까요? [6] 귀여운호랑이10916 23/04/17 10916
170149 [질문] 유튜브 도중 멈춤현상이 반복적으로 일어납니다. [6] 12년째도피중9752 23/04/17 9752
170148 [질문] 회사 이직은 어떻게 하는 것인지요..? [7] 클레멘티아9466 23/04/17 9466
170147 [질문] 티비 항상 켜놓으면 언젠가 폭발할 가능성도 있나요? [16] Pika488716 23/04/17 8716
170146 [질문] 운전사고가 났습니다 [14] 다리미7627 23/04/16 7627
170145 [질문] 30대 중반 남자 패션 질문입니다 [28] rDc6613344 23/04/16 13344
170142 [삭제예정] 자전거를 못 타는 청소년 이상 연령대의 비율은 어느정도일까요? [10] 삭제됨8788 23/04/16 8788
170141 [질문] 직장내 괴롭힘 관련 질문드립니다. [26] Gotetz8599 23/04/16 8599
170140 [질문] 내구성이 좋은 무선마우스 추천 부탁드립니다. [10] 보로미어10367 23/04/16 10367
170139 [질문] 간단한 일본어 회화/영어 회화 책 추천해주실 수 있을까요? 김유라7931 23/04/16 7931
170138 [질문] LG OLED 티비와 소니 헤드셋 연결 질문 입니다 메펠마차박손8015 23/04/16 8015
170137 [질문] 임대아파트 청약기준 및 무주택세대구성원 [2] 너이리와봐8235 23/04/16 8235
170136 [질문] 컴퓨터 본체가 꺼졌다 켜졌다하고 모니터 화면이 안나옵니다. [5] 그때가언제라도12258 23/04/16 12258
170135 [질문] 물리 의문 질문드립니다. [15] 스핔스핔8176 23/04/16 8176
목록 이전 다음
댓글

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