Al tratar de explicar el el problema de Monty Hall a un amigo durante la clase de ayer, terminamos codificándolo en Python para demostrar que si siempre intercambias, ganarás 2/3 veces. Se nos ocurrió esto:

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"

Mi amigo pensó que esta era una buena manera de hacerlo (y es una buena simulación), pero tengo mis dudas y preocupaciones. ¿Es realmente lo suficientemente aleatorio?

El problema que tengo es que todas las opciones están codificadas.

¿Es esta una "simulación" buena o mala para el problema de Monty Hall? ¿Cómo es que?

¿Puedes encontrar una versión mejor?

17
Josh Hunt 8 ago. 2009 a las 07:13

17 respuestas

La mejor respuesta

Su solución está bien, pero si desea una simulación más estricta del problema tal como se plantea (y Python de mayor calidad ;-), intente:

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

Una salida típica es:

Changing has 66721 wins and 33279 losses
IOW, by changing you win 66.7% of the time
37
Jonathan Leffler 8 ago. 2009 a las 05:05

Lea un capítulo sobre el famoso problema de Monty Hall hoy. Esta es mi solución

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
user2490950 17 may. 2016 a las 10:51

Aquí hay una versión interactiva:

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
1
psihodelia 1 sep. 2010 a las 12:13

Monty nunca abre la puerta con el auto, ese es el objetivo del espectáculo (no es tu amigo y tiene conocimiento de lo que hay detrás de cada puerta)

0
Martin Beckett 8 ago. 2009 a las 18:42

Otro ejemplo de código está disponible en: http://standardwisdom.com/softwarejournal/code -samples / monty-hall-python /

El código es un poco más largo y puede que no use algunas de las características interesantes de Python, pero espero que sea agradablemente legible. Usé Python precisamente porque no tenía ninguna experiencia en él, por lo que agradezco los comentarios.

0
Amrinder Arora 22 nov. 2011 a las 10:43

Aquí está mi versión ...

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)) + '%'
2
Acumenus 7 oct. 2017 a las 23:11

Aquí hay una variante diferente que encuentro más intuitiva. ¡Espero que esto ayude!

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)

El aprendizaje sigue siendo el mismo, ese cambio aumenta sus posibilidades de ganar, 0.665025416127 vs 0.33554730611 de la carrera anterior.

0
danielbmathews 10 mar. 2013 a las 21:54

Aquí está mi solución al problema MontyHall implementado en python.

Esta solución hace uso de numpy para la velocidad, también le permite cambiar el número de puertas.

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
0
barukasu 5 jul. 2014 a las 21:00

No había oído hablar del problema de Monty Hall antes de tropezar con esta pregunta. Pensé que era interesante, así que lo leí y creé una simulación en C #. Es un poco tonto ya que simula el programa de juegos y no solo el problema.

Publiqué la fuente y el lanzamiento en codeplex:

http://montyhall.codeplex.com

2
Ronnie Overby 9 sep. 2010 a las 12:09

Encontré que esta es la forma más intuitiva de resolver el problema.

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)

Esto genera algo como

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
user1965074 19 jun. 2015 a las 19:35

Muestra no mia

# -*- 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
1
Tard 9 sep. 2013 a las 07:38

Usted mencionó que todas las opciones están codificadas. Pero si mira más de cerca, notará que lo que cree que son 'elecciones' en realidad no son elecciones. La decisión de Monty es sin pérdida de generalidad ya que siempre elige la puerta con la cabra detrás. Tu intercambio siempre está determinado por lo que elige Monty, y dado que la "elección" de Monty en realidad no fue una elección, tampoco lo es la tuya. Su simulación da los resultados correctos.

2
thedayturns 8 ago. 2009 a las 03:20

Me gusta algo como esto


#!/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
2
si28719e 8 ago. 2009 a las 15:00

Acabo de descubrir que la proporción global de ganar es del 50% y la proporción de perder es del 50% ... Es así como la proporción de ganar o perder se basa en la opción final seleccionada.

  • % De victorias (permanencia): 16.692
  • % De victorias (cambio): 33.525
  • % De pérdidas (permanencia): 33.249
  • % De pérdidas (cambio): 16.534

Aquí está mi código, que difiere del suyo + con comentarios comentados para que pueda ejecutarlo con pequeñas iteraciones:

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))
0
leandr0garcia 20 jul. 2018 a las 13:12

Otra "prueba", esta vez con Python 3. Tenga en cuenta el uso de generadores para seleccionar 1) qué puerta abre Monty y 2) a qué puerta cambia el jugador.

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))
1
Velimir Mlaker 22 jul. 2017 a las 18:08

Aquí hay uno que hice antes:

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)

También tenía código para ejecutar el juego muchas veces, y almacené esto y la salida de muestra en este repositorio.

0
Ellis Percival 17 dic. 2013 a las 18:18

Mi solución con la comprensión de listas para simular el problema.

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

Imprimir simular (N)

1
Arnaldo P. Figueira Figueira 11 ago. 2012 a las 18:58