【问题标题】:Monty Hall simulation not working as intendedMonty Hall 模拟未按预期工作
【发布时间】:2017-06-18 19:52:40
【问题描述】:

我一直在尝试在 Python 中解决 monty hall problem 以推进编码,这就是我尝试将所有内容随机化的原因。问题是:我遇到了一些麻烦。你们中的大多数人可能都知道,蒙蒂问题应该表明,换门的胜率(66%)比留在选定的门(33%)更高。出于某种奇怪的原因,虽然我的模拟显示两种情况下的胜率都是 33%,但我不太确定为什么。

代码如下:

from random import *


def doorPriceRandomizer():
    door1 = randint(0,2) #If a door is defined 0, it has a price in it
    door2 = randint(0,2) #If a door is defined either 1 or 2, it has a goat in it.
    door3 = randint(0,2)
    while door2 == door1:
        door2 = randint(0,2)
    while door3 == door2 or door3 == door1:
        door3 = randint(0,2)
    return door1,door2,door3 #This random placement generator seems to be working fine.


while True:
    loopStart = 0
    amountWin = 0
    amountLose = 0
    try:
        loopEnd = int(input("How often would you like to run this simulation: "))
        if loopEnd < 0:
            raise ValueError
        doorChangeUser = int(input("[0] = Do not change door; [1] = Change door: "))
        if doorChangeUser not in range(0,2):
            raise ValueError
    except ValueError:
            print("Invalid input. Try again.\n")
    else:
        while loopStart != loopEnd:
            gameDoors = doorPriceRandomizer()
            inputUser = randint(0,2)
            if doorChangeUser == 0:
                if gameDoors[inputUser] == 0:
                    amountWin += 1
                    loopStart += 1
                else:
                    amountLose += 1
                    loopStart += 1
            elif doorChangeUser == 1:
                ChangeRandom = 0
                while gameDoors[ChangeRandom] == gameDoors[inputUser]:
                    ChangeRandom = randint(0,2)
                if gameDoors[ChangeRandom] == 0:
                    amountWin += 1
                    loopStart += 1
                else:
                    amountLose += 1
                    loopStart += 1

    print("Win amount: ",amountWin,"\tLose amount: ",amountLose)

我做错了什么?我真的很感激所有的帮助!提前致谢!

【问题讨论】:

  • 欢迎来到 SO:请拨打tour 并阅读minimal reproducible example,以增加获得所需帮助的机会。您发布的代码块应遵循minimal reproducible example 中的指南。
  • 如果有人感兴趣,我做了这个,我把游戏变成了一个函数,所以你可以在一个循环中运行它无数次来获得几率,你可以只调用没有参数的函数玩它。如果您有空闲时间,请查看这对我来说意义重大:github.com/NoahCristino/montyhall

标签: python python-3.x simulation python-3.6


【解决方案1】:
ChangeRandom = 0
while gameDoors[ChangeRandom] == gameDoors[inputUser]:
    ChangeRandom = randint(0,2)

这并不像你认为的那样。这不是检查ChangeRandom 门是否与inputUser 门相同,而是检查ChangeRandom 门和inputUser 门是否具有相同的值——也就是说,它们要么都是赢家,要么是都是失败者。

也就是说,这甚至不是您想要做的。您要做的是找到一扇不是用户输入的门,它是失败者门,然后切换到不是用户输入的其他门。这可以通过对您的代码进行最小的更改来实现:

other_wrong_door = next(c for c, v in enumerate(gameDoors) if v != 0 and c != inputUser)
new_door = next(c for c, _ in enumerate(gameDoors) if c != inputUser and c != other_wrong_door)

但老实说,这值得重新检查您的代码结构。给我几分钟的时间来解决问题,我将编辑此答案,让您了解我将如何实现它。

import random

DOORS = [1, 0, 0]

def runonce(switch=False):
    user_choice = random.choice(DOORS)
    if user_choice == 1:
        # immediate winner
        if switch:
            # if you won before and switch doors, you must lose now
            return False
        else:
            new_doors = [0, 0]  # remove the user-selected winner
            new_doors = [0]     # remove another loser
            return bool(random.choice(new_doors))
            # of course, this is always `0`, but
            # sometimes it helps to show it. In production you
            # wouldn't bother writing the extra lines and just return False
    else:
        if switch:
            new_doors = [1, 0]  # remove the user-selected loser
            new_doors = [1]     # remove another loser
            return bool(random.choice(new_doors))
            # as above: this is always True, but....
        else:
            return False  # if you lost before and don't switch, well, you lost.

num_trials = int(input("How many trials?"))
no_switch_raw = [run_once(switch=False) for _ in range(num_trials)]
switch_raw = [run_once(switch=True) for _ in range(num_trials)]

no_switch_wins = sum(1 for r in no_switch_raw if r)
switch_wins = sum(1 for r in switch_raw if r)

no_switch_prob = no_switch_wins / num_trials * 100.0
switch_prob = switch_wins / num_trials * 100.0

print( "         WINS    LOSSES   %\n"
      f"SWITCH:  {switch_wins:>4}    {num_trials-switch_wins:>6}  {switch_prob:.02f}\n"
      f"NOSWITCH:{no_switch_wins:>4}    {num_trials-no_switch_wins:>6}  {no_switch_prob:.02f}")

【讨论】:

  • 见鬼,这很复杂。稍后我会研究你对这个问题的解决方案,因为我很确定我可以从中学到一些东西。相当多的事情我还不知道.. shuffle 功能就是其中之一。感谢那。现在虽然我试图插入你之前写给我的那两行代码。它有效,但我真的不明白它的作用。介意更详细地解释这两行吗?我试图弄清楚next 做了什么以及for c in c 应该如何工作。没有定义变量的 for 循环如何工作?
  • var for var in collection 是一个 genexp 或生成器表达式。您通常会看到它们用方括号括起来,这使它们成为“列表推导式”[var for var in collection],但由于我们只需要一个值,因此我只使用原始 genexp 并在其上调用 nextnext 是一个从生成器中提取下一个值的内置方法。
  • genexp 中的第一个表达式(第一个var)是从生成器中提取的值。因此,您可以通过 x**2 for x in range(1, 1000) 来生成完美正方形
【解决方案2】:

你弄错了问题的机制,所以你得到了错误的结果。我已经重写了选择机制,但是我将用户输入的东西留给你,这样你就可以继续学习 python。这是解决问题的众多方法之一,但希望它能向您展示一些事情。

def get_choices():
    valid_choices = [0, 1, 2] # these are the values for a valid sample
    shuffle(valid_choices)    # now randomly shuffle that list
    return valid_choices      # return the shuffled list

def get_door(user_choice):
    return user_choice.index(0)


def monty_sim(n, kind):
    """

    :param n: number of runs in this simulation
    :param kind: whether to change the door or not, 0 - don't change, 1 = change door
    :return: (win_rate, 1 - win_rate)
    """
    wins = 0
    for i in range(0, n):
        game_doors = get_choices()
        user_choice = get_door(get_choices()) # use the same method and find user door choice
        # so there are two branches.
        # In both, a door with a goat (game_door = 1) is chosen, which reduce the result to
        # a choice between two doors, rather than 3.
        if kind == 0:
            if user_choice == game_doors.index(0):
                wins += 1
        elif kind == 1:
            # so now, the user chooses to change the door
            if user_choice != game_doors.index(0):
                wins += 1
            # Because the original choice wasn't the right one, then the new
            # must be correct because the host already chose the other wrong one.

    win_rate = (wins / n) * 100
    return win_rate, 100 - win_rate


if __name__ == '__main__':
    n = 1000
    kind = 1
    wins, loses = monty_sim(n, kind)
    print(f'In a simulation of {n} experiments, of type {kind} user won {wins:02f} of the time, lost {loses:02f} of the time')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-19
    • 2020-04-23
    相关资源
    最近更新 更多