通过尝试在昨天的课堂上向朋友解释Monty Hall problem,我们最终用Python编写代码来证明如果你总是交换,你将赢得2/3次。我们想出了这个:
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"
我的朋友认为这是一个很好的方式(并且是一个很好的模拟),但我有疑虑和担忧。这实际上是随机的吗?
我遇到的问题是所有选择都是硬编码的。
这对蒙蒂霍尔问题是一个好的还是坏的'模拟'?怎么来的?
你能想出更好的版本吗?
答案 0 :(得分:37)
你的解决方案很好,但是如果你想要对问题进行更严格的模拟(以及更高质量的Python ;-),请尝试:
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
答案 1 :(得分:2)
你提到所有的选择都是硬编码的。但如果你仔细观察,你会注意到你认为'选择'实际上根本就不是选择。蒙蒂的决定不失一般性,因为他总是选择门背后的山羊。你的交换总是由Monty选择的东西决定,因为Monty的“选择”实际上不是一个选择,你也不是。您的模拟给出了正确的结果..
答案 2 :(得分:2)
我喜欢这样的事情。
#!/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
答案 3 :(得分:2)
在我偶然发现这个问题之前,我没有听说过蒙蒂霍尔问题。我觉得它很有趣,所以我读了它并创建了一个c#模拟。这有点傻,因为它模拟了游戏节目,而不仅仅是问题。
我在codeplex上发布了源代码和发布:
答案 4 :(得分:2)
这是我的版本......
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)) + '%'
答案 5 :(得分:1)
这是一个互动版本:
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
答案 6 :(得分:1)
我的列表理解解决方案来模拟问题
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)
答案 7 :(得分:1)
另一个“证据”,这次是使用Python 3.注意使用生成器来选择1)Monty打开的门,以及2)播放器切换到哪个门。
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))
答案 8 :(得分:1)
不是我的样本
# -*- 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
答案 9 :(得分:1)
今天阅读关于着名的蒙蒂霍尔问题的章节。这是我的解决方案。
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()
答案 10 :(得分:1)
我发现这是解决问题最直观的方式。
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.
答案 11 :(得分:0)
我刚刚发现,全球获胜比例为50%,失败比例为50%...这就是根据选定的最终选项获胜或失败的比例。
这是我的代码,它与您的+和带有注释的注释不同,因此您可以通过小的迭代来运行它:
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))
答案 12 :(得分:0)
答案 13 :(得分:0)
这是我在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
答案 14 :(得分:0)
这是我之前提到的那个:
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)
我还有多次运行游戏的代码,并存储了此示例和示例输出in this repostory。
答案 15 :(得分:0)
这是我发现最直观的不同变体。希望这有帮助!
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.
答案 16 :(得分:0)
另一个代码示例位于:http://standardwisdom.com/softwarejournal/code-samples/monty-hall-python/
代码有点长,可能不会使用Python的一些很酷的功能,但我希望它具有良好的可读性。使用Python正是因为我没有任何经验,所以反馈很受欢迎。