这是一个好的还是坏的“蒙提霍尔”模拟?为什么?

15 投票
15 回答
13246 浏览
提问于 2025-04-15 13:27

昨天在课堂上,我试着给朋友解释蒙提霍尔问题,结果我们用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"

我朋友觉得这个方法不错(而且是个很好的模拟),但我对此有些怀疑和担心。这个模拟真的够随机吗?

我觉得问题在于,所有的选择都是固定写死的。

这个模拟对于蒙提霍尔问题来说是好还是坏?为什么?

你能想出一个更好的版本吗?

15 个回答

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
2

你提到所有的选择都是写死在代码里的。但如果你仔细看看,就会发现你认为的“选择”其实根本不是选择。蒙提的决定是没有损失的一般性,因为他总是选择有山羊的那扇门。你换门的决定总是由蒙提的选择来决定,而蒙提的“选择”实际上并不算选择,所以你的选择也不算选择。你的模拟结果是正确的。

38

你的解决方案很好,但如果你想更严格地模拟这个问题(而且想要更高质量的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

撰写回答