15

昨日の授業中に友人にモンティホール問題を説明しようとした結果、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"

私の友人は、これがそれを実行するための良い方法であると考えました(そしてそれのための良いシミュレーションです)が、私には疑問と懸念があります。それは実際には十分にランダムですか?

私が抱えている問題は、すべての選択肢がハードコーディングされていることです。

これはモンティホール問題の良い「シミュレーション」ですか、それとも悪い「シミュレーション」ですか?どうして?

より良いバージョンを思い付くことができますか?

4

15 に答える 15

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
于 2009-08-08T03:28:15.303 に答える
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
于 2009-08-08T15:00:23.197 に答える
2

すべての選択肢がハードコードされているとおっしゃいましたが、よく見ると、「選択肢」と思われるものが実際にはまったく選択肢ではないことに気付くでしょう。モンティの決定は、彼が常に後ろにヤギがいるドアを選ぶので、一般性を失うことはありません。あなたの交換は常にモンティが何を選択するかによって決定されます、そしてモンティの「選択」は実際には選択ではなかったので、あなたも選択しません。シミュレーションで正しい結果が得られます。

于 2009-08-08T03:20:44.427 に答える
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)) + '%'
于 2015-04-20T14:03:47.883 に答える
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
于 2010-09-01T12:13:41.117 に答える
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))

印刷simulate(N)

于 2012-08-06T17:52:48.593 に答える
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
于 2013-09-09T07:38:04.253 に答える
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.
于 2015-06-19T19:35:17.570 に答える
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()
于 2016-05-17T10:51:41.117 に答える
1

更新されたソリューション

今回はenumモジュールを使用して更新します。繰り返しになりますが、目前の問題にPythonの最も表現力豊かな機能を使用しながら、簡潔にするために次のようにします。

from enum import auto, Enum
from random import randrange, shuffle

class Prize(Enum):
    GOAT = auto()
    CAR = auto()

items = [Prize.GOAT, Prize.GOAT, Prize.CAR]
num_trials = 100000
num_wins = 0

# Shuffle prizes behind doors. Player chooses a random door, and Monty chooses
# the first of the two remaining doors that is not a car. Then the player
# changes his choice to the remaining door that wasn't chosen yet.
# If it's a car, increment the win count.
for trial in range(num_trials):
    shuffle(items)
    player = randrange(len(items))
    monty = next(i for i, p in enumerate(items) if i != player and p != Prize.CAR)
    player = next(i for i in range(len(items)) if i not in (player, monty))
    num_wins += items[player] is Prize.CAR

print(f'{num_wins}/{num_trials} = {num_wins / num_trials * 100:.2f}% wins')

以前のソリューション

今回はPython3を使用した、さらに別の「証拠」です。ジェネレーターを使用して、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))
于 2017-07-22T18:08:26.860 に答える
0

モンティは車でドアを開けることは決してありません-それがショーの要点です(彼はあなたの友人ではなく、各ドアの後ろにあるものについての知識を持っています)

于 2009-08-08T03:17:27.643 に答える
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.33554730611に対して0.665025416127になります。

于 2013-03-10T21:48:45.797 に答える
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)

また、ゲームを何度も実行するコードがあり、これとサンプル出力をこのリポジトリに保存しました。

于 2013-12-17T18:18:54.480 に答える
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
于 2014-07-05T21:00:01.557 に答える
0

世界の勝率が50%、負けの比率が50%であることがわかりました...これは、選択した最終オプションに基づく勝ち負けの比率です。

  • %Wins(滞在):16.692
  • %Wins(スイッチング):33.525
  • %損失(滞在):33.249
  • %損失(切り替え):16.534

これが私のコードです。これはあなたのコードとは異なり、コメント付きのコメントが付いているので、小さな反復で実行できます。

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))
于 2018-07-20T13:12:30.053 に答える