2009-08-08 7 views
17

Próbując wytłumaczyć przyjaciołom z klasy Monty Hall problem podczas wczorajszej lekcji, zakończyliśmy kodowanie w Pythonie, aby udowodnić, że jeśli zawsze zamienisz się, wygrasz 2/3 razy. Wpadliśmy na to:Czy to dobra czy zła "symulacja" dla Monty Hall? Dlaczego?

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" 

Przyjacielu, że to był dobry sposób będzie o nim (i jest to dobry symulacja dla niego), ale mam wątpliwości i obawy. Czy rzeczywiście jest wystarczająco losowy?

Problem mam z nim jest to, że wszystkie wybory są niby twardy kodowane.

Czy to dobry czy zły „symulacja” dla problemu Monty Hall? Dlaczego?

Czy możesz wymyślić lepszą wersję?

+0

co próbujesz osiągnąć? –

+0

Mitch: Dokładny sposób udowodnienia, że ​​masz 2/3 szanse na wygraną, pod warunkiem, że zamienisz drzwi. –

+4

Udowodnij to matematycznie. Dane empiryczne nigdy nie mogą być użyte do dowodu, mogą być wykorzystane jako dowód lub wsparcie. – ldog

Odpowiedz

36

Twoje rozwiązanie jest w porządku, ale jeśli chcesz surowszy symulację problemu, jakie (i nieco wyższej jakości Python ;-), spróbuj:

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 

się typowa wydajność:

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

Nie jestem pewien, czy rozumiem, dlaczego masz dla k w części sekwencji? Nawet nie wybierasz k, i nie ma znaczenia, które drzwi wybierają monty ... wszystko, co ma znaczenie, to "n", prawda? – Tom

+9

@Tom, po prostu próbuję bardzo wiernie symulować klasyczne zdanie Monty Hall Problem - Monty wybiera drzwi (inne niż oryginalny pick, a nie ten w samochodzie) i albo się zmieniasz, albo nie. Tak, ruch Monty'ego w obrębie podanych ograniczeń jest nieistotny (jak pokazuje fakt, że k nie pojawia się w ogonie pętli ;-), więc cały blok może zostać usunięty, Z WYJĄTKIEM, że cały punkt wykonywanego pseudokodu to prawdopodobnie w celu przekonania sceptyków, więc im bardziej trzymamy się litery problemu, tym lepiej! -) –

+0

@Alex: ok, wystarczy sprawdzić :-). miła odpowiedź, +1. – Tom

0

Monty nigdy nie otwiera drzwi samochodu - to cały punkt show (on nie jest twoim przyjacielem HAS wiedzę o tym, co znajduje się za każdymi drzwiami)

+3

Frickin 'Monty! Co za palant. – zombat

+7

Nie - nigdy nie otwiera drzwi samochodem! –

+0

Przepraszam, że zwykle jest na odwrót - najważniejszą kwestią (która zaginęła u większości osób używających tego w wywiadach) jest to, że Monty nie radzi sobie z ranom –

2

Wspomniałeś, że wszystkie wybory są sztywno in. Ale jeśli przyjrzysz się bliżej, zauważysz, że to, co uważasz za "wybory", w rzeczywistości wcale nie jest wyborem. Decyzja Monty jest bez utraty ogólności, ponieważ zawsze wybiera drzwi z kozą za nim. Twoja zamiana jest zawsze determinowana przez to, co wybiera Monty, a skoro "wybór" Monty'ego w rzeczywistości nie był wyborem, nie jest też twój. Symulacji daje poprawne wyniki ..

+0

W rzeczywistości, jeśli rozpoczniesz od ścisłej symulacji i zoptymalizujesz swoją drogę w dół, otrzymasz kod, który po prostu zwraca prawdę w 67% przypadków. Jest to prawdopodobnie jeden z najlepszych sposobów, aby przekonać kogoś o tym problemie. Poproś, aby zaprogramowali symulację.Zobaczą, że piszą głupi i zbędny kod. – Cruncher

2

Podoba mi się coś takiego.


#!/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 
1

Oto interaktywna wersja:

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 
2

nie słyszał o Monty Hall problem przed natknąłem to pytanie. Myślałem, że to interesujące, więc przeczytałem o tym i stworzyłem symulację C#. To trochę idiotyczne, ponieważ symuluje grę, a nie tylko problem.

wydałem źródło i zwolnić na CodePlex:

http://montyhall.codeplex.com

1

Moje rozwiązanie z listowego do symulacji problemu

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)) 

wydruku Symulacja (N)

0

Oto inny wariant znajdę najbardziej intuicyjne. Mam nadzieję że to pomoże!

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) 

Nauka jest wciąż ten sam, że przełączanie zwiększa swoje szanse na wygraną, 0.665025416127 vs 0.33554730611 z powyższym okresie.

1

Nie moja próbka

# -*- 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 
0

Oto jeden zrobiłem wcześniej:

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) 

miałem też kod, aby uruchomić grę wiele razy, i to zapisane i wyjście próbki in this repostory.

0

Oto moje rozwiązanie problemu MontyHall zaimplementowanego w Pythonie.

To rozwiązanie wykorzystuje numpy do prędkości, a także pozwala zmienić liczbę drzwi.

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 
2

Oto moja wersja ...

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)) + '%' 
1

I okazało się, że najbardziej intuicyjny sposób rozwiązania problemu.

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) 

ten wyprowadza coś

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

przeczytaj rozdział o słynnym problemu Monty Hall dzisiaj. To jest moje rozwiązanie.

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() 
1

Kolejny „dowód”, tym razem z Pythona 3. Zwróć uwagę na użycie generatorów do wyboru 1), który otwiera drzwi Monty i 2), które drzwi gracz przełącza się.

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)) 
Powiązane problemy