用Python解决蒙提霍尔问题

1 投票
2 回答
1102 浏览
提问于 2025-04-20 18:32

我正在尝试理解蒙提霍尔问题的这个解决方案,我大部分代码都明白了,但有两个地方我卡住了。

下面是代码,但我特别卡在这两个部分

result[bad] = np.random.randint(0,3, bad.sum())

还有整个 switch_guess 函数。

如果有人能用简单易懂的语言给我解释一下,那就太好了。

#Simulates picking a prize door
def simulate_prizedoor(nsim):
    return np.random.randint(0,3,(nsim))

#Simulates the doors guessed
def simulate_guesses(nsim):
    return np.zeros(nsim, dtype=np.int)

#Simulates the "game host" showing whats behind a door
def goat_door(prize_doors, guesses):
    result = np.random.randint(0,3, prize_doors.size)
    while True:
        bad = (result == prize_doors) | (result == guesses)
        if not bad.any():
            return result
    result[bad] = np.random.randint(0,3, bad.sum())

#Used to change your guess
def switch_guess(guesses, goat_doors):
    result = np.zeros(guesses.size)
    switch = {(0, 1): 2, (0, 2): 1, (1, 0): 2, (1, 2): 1, (2, 0): 1, (2, 1): 0}
    for i in [0,1,2]:
        #print "i = ", i
        for j in [0,1,2]:
            #print "j = ", j
            mask = (guesses == i) & (goat_doors == j)
            #print "mask = ", mask
            if not mask.any():
                continue
            result = np.where(mask, np.ones_like(result) * switch[(i, j)], result)
    return result

#Calculates the win percentage
def win_percentage(guesses, prizedoors):
    return 100 * (guesses == prizedoors).mean()

#The code to pull everything together
nsim = 10000

#keep guesses
print "Win percentage when keeping original door"
print win_percentage(simulate_prizedoor(nsim), simulate_guesses(nsim))

#switch
pd = simulate_prizedoor(nsim)
guess = simulate_guesses(nsim)
goats = goat_door(pd, guess)
guess = switch_guess(guess, goats)
print "Win percentage when switching doors"
print win_percentage(pd, guess)

2 个回答

0

这也让我困惑,直到五分钟前我终于搞明白了。既然第一个问题已经解决了,我就只谈第二个。

简单来说:给定一系列的(猜测,山羊门),在(i,j)循环中,总会有一些模拟(比如说,simulation[0]和simulation[5])被(i,j)“命中”,也就是说,第0个和第5个模拟的猜测是i,山羊门是j。

变量mask在这个例子中记录了0和5。然后第0个和第5个的结果就可以确定,因为在这些模拟中,唯一可以切换的门是由i和j决定的。所以np.where会更新这些模拟的结果,而其他模拟则保持不变。

以上就是我的直觉。如果你想理解我在说什么,你需要知道np.where是怎么工作的。祝你好运。

2

… 具体来说,我在这两个部分卡住了

result[bad] = np.random.randint(0,3, bad.sum())

我们来把这个问题拆分开。可以把那个 10000 改成一个小一点的数字,比如 5,这样你就可以打印出这些值(可以用 print 函数,或者在调试器里查看),看看发生了什么。

当我们开始这个函数时,prize_doors 会有 5 个从 02 的随机值,比如 2 2 0 1 2,而 guesses 会有 5 个值,全部是 0,像 0 0 0 0 0。所以,result 一开始会有 5 个随机值,从 0 到 2,比如 0 2 2 0 1

每次第一次进入循环时,bad 会是一个包含 5 个 bool 值的列表,如果 result 中的值和 prize_doorsguesses 中的对应值匹配,那么这个值就是 True。所以在这个例子中,bad 可能是 True True False True False,因为第一个猜测和 prize_doors 匹配,而第 0 和第 3 个猜测和 goats 匹配。

不幸的是,我们会一直在这个循环里转,因为循环里面没有任何东西会改变 result,所以 bad 会永远保持不变,而一直做同样的检查总是会返回相同的值。


但是,如果你把那行 result[bad] = … 缩进到循环里面,那就完全不同了。所以,我们假设这就是你应该做的,只是复制错了。

TrueFalse 被当作数字时,它们的值分别是 10。所以,bad.sum() 就是计算 bad 中有多少个匹配的值——在这个例子中是 3

因此,np.random.randint(0, 3, bad.sum()) 会从 02 中随机选择 3 个值,比如 1 0 1

现在,result[bad] 会选择 result 中所有对应 badTrue 的元素,所以在这个例子中是 result[0]result[1]result[3]

所以我们把 1 0 1 赋值给这三个选中的位置,结果 result 现在变成了 1 0 2 1 1

接下来再进入循环时,bad 现在是 True False False False False。我们还有至少一个 True 值,所以再次执行 result[bad] = 这一行。这次,bad.sum()1,所以我们随机选择 1 个值,比如 0,然后把这个值赋给 result[0],所以 result 现在变成了 0 0 2 1 1

下次进入时,bad 现在是 False False False False False,所以 bad.any()False,这就结束了。

换句话说,每次循环中,我们都会把那些不匹配奖品门或山羊门的值选出来,并为它们选择一个新门,直到最后没有这样的值为止。

撰写回答