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}')
목록 삭게로! 맨위로
번호 제목 이름 날짜 조회
168999 [질문] 노트북 추천부탁드립니다. [25] 스핔스핔8880 23/02/14 8880
168330 [질문] 코딩대로 자동으로 움직이는 지그를 만들어 보고 싶습니다. [4] 어센틱8675 23/01/09 8675
168084 [질문] 컴퓨터 견적 브레이크 + 질문입니다 [13] 대한민국육군병장10526 22/12/27 10526
167856 [질문] 파이썬으로 몬티홀 문제 시뮬레이션 해보고 있는데 조언 부탁드립니다 [26] NSpire CX II9002 22/12/16 9002
167668 [질문] 개발자분들 이상황이라면 어떻게 하실건가요? [10] 그림속동화8747 22/12/06 8747
166624 [질문] AI/ 머신러닝 관련 배울 수 있는 책 추천 받을 수 있을까요? [6] norrell8758 22/10/14 8758
166401 [질문] 분당 판교쪽 성인 코딩학원이 있을까요? [4] 트라팔가 로우7238 22/10/02 7238
166333 [질문] 메모리가 충분한데 계속 메모리 부족 현상이 나타납니다 [24] 봄날엔9640 22/09/28 9640
166194 [질문] 노트북 ssd추가, 액정필름 어떤 제품이 좋을까요? [8] BlueSKY--9948 22/09/21 9948
166033 [질문] 노트북 추천 부탁드립니다 [4] scscsc8275 22/09/14 8275
165270 [질문] [vue js] vue 초보질문. 라디오버튼으로 탭효과 [2] Mindow3147 22/08/05 3147
165102 [질문] 엑셀에서 시그마(n:1~N) f(n) 구현하려면 코딩해야하나요? [6] 스핔스핔8126 22/07/28 8126
164935 [질문] 교육과정에 필수로 들어가면 좋겠다 싶은 내용이 있으신가요? [30] 물뿔소7522 22/07/20 7522
164598 [질문] Asus 노트북 질문드립니다. 젠북 vs 비버북 [3] 까만고양이4502 22/07/03 4502
164194 [질문] OTT업체들 화질이 원래 안좋은건가요? [8] 카오루6807 22/06/14 6807
164138 [질문] 컴퓨터 공학,구조 공부와 프로그래밍과의 관계 질문드립니다 [8] 잠이온다4977 22/06/11 4977
163992 [질문] 맥 및 윈도우 모니터 선택장애 [5] 그림속동화3449 22/06/02 3449
163766 [질문] 코딩용 노트북 추천 부탁드립니다. [6] Gotetz4208 22/05/23 4208
163706 [질문] 실험실 홈페이지 도메인 [4] Titleist3224 22/05/20 3224
163520 [질문] CPU와 메인보드 질문입니다. [6] 봄날엔3304 22/05/11 3304
163294 [질문] 코딩 질문 하나만요 ㅠㅠ [7] 삭제됨3437 22/04/29 3437
163263 [질문] 엑셀에서 보이는부분만 붙혀넣는 방법이 있을까요?? [14] 사는게젤힘드러5893 22/04/27 5893
162847 [질문] 노트북(이번에 나온 LG 그램) 메모리 16과 32기가 차이가 어느정도일까요? [6] BlueSKY--5911 22/04/07 5911
목록 이전 다음
댓글

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