이것은 몬티 홀에게 좋은 '시뮬레이션'인가요, 아니면 나쁜가요?왜요?

StackOverflow https://stackoverflow.com/questions/1247863

문제

설명하려는 노력을 통해 몬티홀 문제 어제 수업 중에 친구에게 말했는데, 우리는 항상 바꾸면 2/3배 승리한다는 것을 증명하기 위해 Python으로 코딩했습니다.우리는 이것을 생각해냈습니다:

import random as r

#iterations = int(raw_input("How many iterations? >> "))
iterations = 100000

doors = ["goat", "goat", "car"]
wins = 0.0
losses = 0.0

for i in range(iterations):
    n = r.randrange(0,3)

    choice = doors[n]
    if n == 0:
        #print "You chose door 1."
        #print "Monty opens door 2. There is a goat behind this door."
        #print "You swapped to door 3."
        wins += 1
        #print "You won a " + doors[2] + "\n"
    elif n == 1:
        #print "You chose door 2."
        #print "Monty opens door 1. There is a goat behind this door."
        #print "You swapped to door 3."
        wins += 1
        #print "You won a " + doors[2] + "\n"
    elif n == 2:
        #print "You chose door 3."
        #print "Monty opens door 2. There is a goat behind this door."
        #print "You swapped to door 1."
        losses += 1
        #print "You won a " + doors[0] + "\n"
    else:
        print "You screwed up"

percentage = (wins/iterations) * 100
print "Wins: " + str(wins)
print "Losses: " + str(losses)
print "You won " + str(percentage) + "% of the time"

내 친구는 이것이 좋은 방법이라고 생각했지만(그리고 좋은 시뮬레이션임) 나는 의구심과 우려가 있습니다.실제로는 충분히 무작위인가요?

내가 가진 문제는 모든 선택 사항이 일종의 하드 코딩되어 있다는 것입니다.

이것이 몬티홀 문제에 대한 좋은 '시뮬레이션'인가요, 아니면 나쁜가요?왜요?

더 나은 버전을 생각해 낼 수 있습니까?

도움이 되었습니까?

해결책

솔루션은 괜찮지 만 문제에 대한 엄격한 시뮬레이션을 원한다면 (그리고 다소 고품질의 파이썬 ;-), 시도하십시오.

import random

iterations = 100000

doors = ["goat"] * 2 + ["car"]
change_wins = 0
change_loses = 0

for i in xrange(iterations):
    random.shuffle(doors)
    # you pick door n:
    n = random.randrange(3)
    # monty picks door k, k!=n and doors[k]!="car"
    sequence = range(3)
    random.shuffle(sequence)
    for k in sequence:
        if k == n or doors[k] == "car":
            continue
    # now if you change, you lose iff doors[n]=="car"
    if doors[n] == "car":
        change_loses += 1
    else:
        change_wins += 1

print "Changing has %s wins and %s losses" % (change_wins, change_loses)
perc = (100.0 * change_wins) / (change_wins + change_loses)
print "IOW, by changing you win %.1f%% of the time" % perc

일반적인 출력은 다음과 같습니다.

Changing has 66721 wins and 33279 losses
IOW, by changing you win 66.7% of the time

다른 팁

당신은 모든 선택이 하드 코딩된다고 언급했습니다. 그러나 더 자세히 보면, 당신이 '선택이라고 생각하는 것이 실제로 선택이 아니라는 것을 알 수 있습니다. Monty의 결정은 항상 염소 뒤에 문을 선택하기 때문에 일반성을 잃지 않습니다. 당신의 교환은 항상 Monty가 선택한 것에 의해 결정되며 Monty의 "선택"은 실제로 선택이 아니기 때문에 당신의 것도 아닙니다. 시뮬레이션은 올바른 결과를 제공합니다 ..

나는 이런 것을 좋아한다.


#!/usr/bin/python                                                                                                            
import random
CAR   = 1
GOAT  = 0

def one_trial( doors, switch=False ):
    """One trial of the Monty Hall contest."""

    random.shuffle( doors )
    first_choice = doors.pop( )
    if switch==False:
        return first_choice
    elif doors.__contains__(CAR):
        return CAR
    else:
        return GOAT


def n_trials( switch=False, n=10 ):
    """Play the game N times and return some stats."""
    wins = 0
    for n in xrange(n):
        doors = [CAR, GOAT, GOAT]
        wins += one_trial( doors, switch=switch )

    print "won:", wins, "lost:", (n-wins), "avg:", (float(wins)/float(n))


if __name__=="__main__":
    import sys
    n_trials( switch=eval(sys.argv[1]), n=int(sys.argv[2]) )

$ ./montyhall.py True 10000
won: 6744 lost: 3255 avg: 0.674467446745

나는이 질문을 발견하기 전에 Monty Hall 문제에 대해 들어 본 적이 없다. 나는 그것이 흥미 롭다고 생각했기 때문에 그것에 대해 읽고 AC# 시뮬레이션을 만들었습니다. 문제가 아니라 게임 쇼를 시뮬레이션하기 때문에 일종의 구피입니다.

CodePlex에 소스와 릴리스를 게시했습니다.

http://montyhall.codeplex.com

여기 내 버전이 있습니다 ...

import random

wins = 0

for n in range(1000):

    doors = [1, 2, 3]

    carDoor     = random.choice(doors)
    playerDoor  = random.choice(doors)
    hostDoor    = random.choice(list(set(doors) - set([carDoor, playerDoor])))

    # To stick, just comment out the next line.
    (playerDoor, ) = set(doors) - set([playerDoor, hostDoor]) # Player swaps doors.

    if playerDoor == carDoor:
        wins += 1

print str(round(wins / float(n) * 100, 2)) + '%'

대화식 버전은 다음과 같습니다.

from random import shuffle, choice
cars,goats,iters= 0, 0, 100
for i in range(iters):
    doors = ['goat A', 'goat B', 'car']
    shuffle(doors)
    moderator_door = 'car'
    #Turn 1:
    selected_door = choice(doors)
    print selected_door
    doors.remove(selected_door)
    print 'You have selected a door with an unknown object'
    #Turn 2:
    while moderator_door == 'car':
        moderator_door = choice(doors)
    doors.remove(moderator_door)
    print 'Moderator has opened a door with ', moderator_door
    #Turn 3:
    decision=raw_input('Wanna change your door? [yn]')
    if decision=='y':
        prise = doors[0]
        print 'You have a door with ', prise
    elif decision=='n':
        prise = selected_door
        print 'You have a door with ', prise
    else:
        prise = 'ERROR'
        iters += 1
        print 'ERROR:unknown command'
    if prise == 'car':
        cars += 1
    elif prise != 'ERROR':
        goats += 1
print '==============================='
print '          RESULTS              '
print '==============================='
print 'Goats:', goats
print 'Cars :', cars

문제를 시뮬레이션하기위한 목록 이해력이있는 내 솔루션

from random import randint

N = 1000

def simulate(N):

    car_gate=[randint(1,3) for x in range(N)]
    gate_sel=[randint(1,3) for x in range(N)]

    score = sum([True if car_gate[i] == gate_sel[i] or ([posible_gate for posible_gate in [1,2,3] if posible_gate != gate_sel[i]][randint(0,1)] == car_gate[i]) else False for i in range(N)])

    return 'you win %s of the time when you change your selection.' % (float(score) / float(N))

인쇄 시뮬레이션 (n)

내 샘플이 아닙니다

# -*- coding: utf-8 -*-
#!/usr/bin/python -Ou
# Written by kocmuk.ru, 2008
import random

num = 10000  # number of games to play
win = 0      # init win count if donot change our first choice

for i in range(1, num):                            # play "num" games
    if random.randint(1,3) == random.randint(1,3): # if win at first choice 
        win +=1                                    # increasing win count

print "I donot change first choice and win:", win, " games"   
print "I change initial choice and win:", num-win, " games" # looses of "not_change_first_choice are wins if changing

나는 이것이 문제를 해결하는 가장 직관적 인 방법이라는 것을 알았습니다.

import random

# game_show will return True/False if the participant wins/loses the car:
def game_show(knows_bayes):

    doors = [i for i in range(3)]

    # Let the car be behind this door
    car = random.choice(doors)

    # The participant chooses this door..
    choice = random.choice(doors)

    # ..so the host opens another (random) door with no car behind it
    open_door = random.choice([i for i in doors if i not in [car, choice]])

    # If the participant knows_bayes she will switch doors now
    if knows_bayes:
        choice = [i for i in doors if i not in [choice, open_door]][0]

    # Did the participant win a car?
    if choice == car:
        return True
    else:
        return False

# Let us run the game_show() for two participants. One knows_bayes and the other does not.
wins = [0, 0]
runs = 100000
for x in range(0, runs):
    if game_show(True):
        wins[0] += 1
    if game_show(False):
        wins[1] += 1

print "If the participant knows_bayes she wins %d %% of the time." % (float(wins[0])/runs*100)
print "If the participant does NOT knows_bayes she wins %d %% of the time." % (float(wins[1])/runs*100)

이것은 같은 것을 출력합니다

If the participant knows_bayes she wins 66 % of the time.
If the participant does NOT knows_bayes she wins 33 % of the time.

오늘 유명한 Monty Hall 문제에 대한 장을 읽으십시오. 이것은 내 해결책입니다.

import random

def one_round():
    doors = [1,1,0] # 1==goat, 0=car
    random.shuffle(doors) # shuffle doors
    choice = random.randint(0,2) 
    return doors[choice] 
    #If a goat is chosen, it means the player loses if he/she does not change.
    #This method returns if the player wins or loses if he/she changes. win = 1, lose = 0

def hall():
    change_wins = 0
    N = 10000
    for index in range(0,N):
        change_wins +=  one_round()
    print change_wins

hall()

이번에는 Python 3과 함께 또 다른 "증거"를 선택하십시오.

import random

items = ['goat', 'goat', 'car']
num_trials = 100000
num_wins = 0

for trial in range(num_trials):
    random.shuffle(items)
    player = random.randrange(3)
    monty = next(i for i, v in enumerate(items) if i != player and v != 'car')
    player = next(x for x in range(3) if x not in (player, monty))
    if items[player] == 'car':
        num_wins += 1

print('{}/{} = {}'.format(num_wins, num_trials, num_wins / num_trials))

Monty는 차로 문을 열지 않습니다 - 그것은 쇼의 요점입니다 (그는 당신의 친구가 아니에요. 각 문 뒤에 무엇이 있는지에 대한 지식이 없습니다)

다른 코드 샘플은 다음과 같습니다. http://standardwisdom.com/softwarejournal/code-samples/monty-hall-python/

코드는 조금 길고 Python의 멋진 기능 중 일부를 사용하지 않을 수 있지만 읽을 수 있기를 바랍니다. 경험이 없었기 때문에 Python을 정확하게 사용 했으므로 피드백에 감사드립니다.

내가 가장 직관적이라고 생각하는 다른 변형은 다음과 같습니다.도움이 되었기를 바랍니다!

import random

class MontyHall():
    """A Monty Hall game simulator."""
    def __init__(self):
        self.doors = ['Door #1', 'Door #2', 'Door #3']
        self.prize_door = random.choice(self.doors)
        self.contestant_choice = ""
        self.monty_show = ""
        self.contestant_switch = ""
        self.contestant_final_choice = ""
        self.outcome = ""

    def Contestant_Chooses(self):
        self.contestant_choice = random.choice(self.doors)

    def Monty_Shows(self):
        monty_choices = [door for door in self.doors if door not in [self.contestant_choice, self.prize_door]]
        self.monty_show = random.choice(monty_choices)

    def Contestant_Revises(self):
        self.contestant_switch = random.choice([True, False])
        if self.contestant_switch == True:
            self.contestant_final_choice = [door for door in self.doors if door not in [self.contestant_choice, self.monty_show]][0]
        else:
            self.contestant_final_choice = self.contestant_choice

    def Score(self):
        if self.contestant_final_choice == self.prize_door:
            self.outcome = "Win"
        else:
            self.outcome = "Lose"

    def _ShowState(self):
        print "-" * 50
        print "Doors                    %s" % self.doors
        print "Prize Door               %s" % self.prize_door
        print "Contestant Choice        %s" % self.contestant_choice
        print "Monty Show               %s" % self.monty_show
        print "Contestant Switch        %s" % self.contestant_switch
        print "Contestant Final Choice  %s" % self.contestant_final_choice
        print "Outcome                  %s" % self.outcome
        print "-" * 50



Switch_Wins = 0
NoSwitch_Wins = 0
Switch_Lose = 0
NoSwitch_Lose = 0

for x in range(100000):
    game = MontyHall()
    game.Contestant_Chooses()
    game.Monty_Shows()
    game.Contestant_Revises()
    game.Score()
    # Tally Up the Scores
    if game.contestant_switch  and game.outcome == "Win":  Switch_Wins = Switch_Wins + 1
    if not(game.contestant_switch) and game.outcome == "Win":  NoSwitch_Wins = NoSwitch_Wins + 1
    if game.contestant_switch  and game.outcome == "Lose": Switch_Lose = Switch_Lose + 1
    if not(game.contestant_switch) and game.outcome == "Lose": NoSwitch_Lose = NoSwitch_Lose + 1

print Switch_Wins * 1.0 / (Switch_Wins + Switch_Lose)
print NoSwitch_Wins * 1.0 / (NoSwitch_Wins + NoSwitch_Lose)

학습 내용은 여전히 ​​동일합니다. 전환하면 위의 실행에서 0.665025416127 대 0.33554730611로 승리 확률이 높아집니다.

내가 이전에 만든 것입니다.

import random

def game():
    """
    Set up three doors, one randomly with a car behind and two with
    goats behind. Choose a door randomly, then the presenter takes away
    one of the goats. Return the outcome based on whether you stuck with
    your original choice or switched to the other remaining closed door.
    """
    # Neither stick or switch has won yet, so set them both to False
    stick = switch = False
    # Set all of the doors to goats (zeroes)
    doors = [ 0, 0, 0 ]
    # Randomly change one of the goats for a car (one)
    doors[random.randint(0, 2)] = 1
    # Randomly choose one of the doors out of the three
    choice = doors[random.randint(0, 2)]
    # If our choice was a car (a one)
    if choice == 1:
        # Then stick wins
        stick = True
    else:
        # Otherwise, because the presenter would take away the other
        # goat, switching would always win.
        switch = True
    return (stick, switch)

또한 게임을 여러 번 실행하는 코드가 있었고 이것과 샘플 출력을 저장했습니다. 이 재건에서.

다음은 Python에서 구현 된 Montyhall 문제에 대한 솔루션입니다.

이 솔루션은 Numpy를 사용하여 속도를 사용하며 문 수를 변경할 수 있습니다.

def montyhall(Trials:"Number of trials",Doors:"Amount of doors",P:"Output debug"):
    N = Trials # the amount of trial
    DoorSize = Doors+1
    Answer = (nprand.randint(1,DoorSize,N))

    OtherDoor = (nprand.randint(1,DoorSize,N))

    UserDoorChoice = (nprand.randint(1,DoorSize,N))

    # this will generate a second door that is not the user's selected door
    C = np.where( (UserDoorChoice==OtherDoor)>0 )[0]
    while (len(C)>0):
        OtherDoor[C] = nprand.randint(1,DoorSize,len(C))
        C = np.where( (UserDoorChoice==OtherDoor)>0 )[0]

    # place the car as the other choice for when the user got it wrong
    D = np.where( (UserDoorChoice!=Answer)>0 )[0]
    OtherDoor[D] = Answer[D]

    '''
    IfUserStays = 0
    IfUserChanges = 0
    for n in range(0,N):
        IfUserStays += 1 if Answer[n]==UserDoorChoice[n] else 0
        IfUserChanges += 1 if Answer[n]==OtherDoor[n] else 0
    '''
    IfUserStays = float(len( np.where((Answer==UserDoorChoice)>0)[0] ))
    IfUserChanges = float(len( np.where((Answer==OtherDoor)>0)[0] ))

    if P:
        print("Answer        ="+str(Answer))
        print("Other         ="+str(OtherDoor))
        print("UserDoorChoice="+str(UserDoorChoice))
        print("OtherDoor     ="+str(OtherDoor))
        print("results")
        print("UserDoorChoice="+str(UserDoorChoice==Answer)+" n="+str(IfUserStays)+" r="+str(IfUserStays/N))
        print("OtherDoor     ="+str(OtherDoor==Answer)+" n="+str(IfUserChanges)+" r="+str(IfUserChanges/N))

    return IfUserStays/N, IfUserChanges/N

방금 승리의 글로벌 비율이 50%이고 잃어버린 비율은 50%라는 것을 알았습니다. 선택한 최종 옵션을 기준으로 승리 또는 손실에 대한 비율이 방법입니다.

  • %승리 (체재) : 16.692
  • %승리 (스위칭) : 33.525
  • %손실 (체재) : 33.249
  • %손실 (스위칭) : 16.534

다음은 내 코드입니다. 귀하의 코드와는 다른 댓글이있는 댓글과는 다른 작은 반복으로 실행할 수 있습니다.

import random as r

#iterations = int(raw_input("How many iterations? >> "))
iterations = 100000

doors = ["goat", "goat", "car"]
wins_staying =  0
wins_switching = 0  
losses_staying =  0
losses_switching = 0  



for i in range(iterations):
    # Shuffle the options
    r.shuffle(doors)
    # print("Doors configuration: ", doors)

    # Host will always know where the car is 
    car_option = doors.index("car")
    # print("car is in Option: ", car_option)

    # We set the options for the user
    available_options = [0, 1 , 2]

    # The user selects an option
    user_option = r.choice(available_options)
    # print("User option is: ", user_option)

    # We remove an option
    if(user_option != car_option ) :
        # In the case the door is a goat door on the user
        # we just leave the car door and the user door
        available_options = [user_option, car_option]
    else:
        # In the case the door is the car door 
        # we try to get one random door to keep
        available_options.remove(available_options[car_option])
        goat_option = r.choice(available_options)
        available_options = [goat_option, car_option]


    new_user_option = r.choice(available_options)
    # print("User final decision is: ", new_user_option)

    if new_user_option == car_option :
        if(new_user_option == user_option) :
            wins_staying += 1
        else :
            wins_switching += 1    
    else :
        if(new_user_option == user_option) :
            losses_staying += 1
        else :
            losses_switching += 1 


print("%Wins (staying): " + str(wins_staying / iterations * 100))
print("%Wins (switching): " + str(wins_switching / iterations * 100))
print("%Losses (staying) : " + str(losses_staying / iterations * 100))
print("%Losses (switching) : " + str(losses_switching / iterations * 100))
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top