Una variant del problema de Monty Hall (divertiment courserià)

Els cursos de Coursera estan resultant ser una de les coses més divertides que he fet últimament. Estic apuntat al MOOC Financial Engineering and Risk Management II i fa un parell de setmanes un dels exercicis era una adaptació de “El problema de Monty Hall“. Que ningú s’esveri: és un problema de probabilitats que es pot resoldre amb coneixements de batxillerat.

De la Viquipèdia:
“El problema de Monty Hall és un trencaclosques de probabilitat basat en el programa de televisió americà Let’s Make a Deal (“Fem un tracte”). El nom ve del presentador del programa, Monty Hall. El problema també s’anomena la paradoxa de Monty Hall.

hall_lmad

Una explicació coneguda del problema va ser publicada a la revista Parade:

«Suposa que ets al programa “Fem un tracte” i et deixen triar una de tres portes. Darrere una, hi ha un cotxe; darrere de les altres, cabres. Tries una porta, per exemple, la número 1, i Monty Hall que sap què hi ha darrere les portes obre una altra porta, per exemple la 3, que té una cabra. Després et diu: “Vols canviar a la 2?”

Hi surts guanyant si canvies el que havies triat? (Whitaker 1990)»

Com que no hi ha manera de saber quina de les dues portes no obertes és la guanyadora, la majoria de la gent creu que cada porta té les mateixes probabilitats i conclou que canviar de porta no importa. Però aquesta conclusió és incorrecta: de fet si el jugador canvia la probabilitat de guanyar passa d’1/3 a 2/3. Canviar no dóna cap avantatge si el jugador tria inicialment la porta guanyadora, el que té una probabilitat d’1/3. Triar inicialment la porta incorrecta té una probabilitat de 2/3; quan es revela l’altra porta incorrecta, canviar suposa guanyar. Així, la probabilitat de guanyar quan es canvia de porta és de 2/3.

Quan la solució del problema va aparèixer a la revista Parade, aproximadament 10.000 lectors, incloent uns 1.000 amb doctorat, van escriure a la revista dient que la resposta era incorrecta. Molta part de la controvèrsia fou perquè la versió de la revista del problema és tècnicament ambigua ja que hi ha aspectes que el presentador no explica, com que ha d’obrir una porta i ha d’oferir al concursant si vol canviar de porta.”

Doncs bé, al MOOC de Financial Engineering and Risk Managemnent II de Coursera, actualment en curs, han plantejat en un exercici una variació del problema de Monty Hall:

«Suposa que ets al programa “Fem un tracte” i et deixen triar una de quatre portes: dues amaguen cotxes i darrere les altres dues, hi han cabres. Tries una porta, per exemple, la número 1, i Monty Hall que sap què hi ha darrere les portes obre una altra porta, per exemple la 3, que té una cabra. Després et diu: “Vols canviar de porta?”

La probabilitat que el concursant triï una porta amb cotxe el primer cop és 1/2.

Què canvia quan el presentador obre una de les altres tres i mostra una cabra?

La tria del jugador afecta a la porta que obre el presentador. Que el presentador obri una porta no es un esdeveniment totalment aleatori ni inconnex.

Si el concursant tria en la seva primera opció una porta amb cotxe (probabilitat 1/2), aleshores el presentador pot obrir dues de les tres portes que resten tancades. El jugador té probabilitats de guanyar el cotxe si canvia en la segona tria a una de les altres dues portes tancades, que amaguen un cotxe (probabilitat d’aquesta segona tria, doncs, 1/2)

Si el concursant ha triat una porta amb cabra en la seva primera opció (probabilitat 1/2), el presentador només pot obrir una de les altres tres portes, l’única que amagarà una cabra. Les altres dues portes amaguen un cotxe. Si el concursant canvia de porta, guanya segur (probabilitat d’aquesta segona tria igual a 1).

Resumint: si manté la tria original guanya només si la primera porta amagava un cotxe (amb probabilitat de 1/2).

Si canvia:
Guanya segur si en la primera opció ha triat una porta que amaga una cabra, perquè les altres portes tancades amaguen dos cotxes. (probabilitat = 1)
Si la porta de la tria inicial amagava un cotxe, la probabilitat de triar l’altre cotxe al canviar és de 1/2, perquè pot triar entre entre les altres dues portes, que amaguen un cotxe i una cabra.

Matemàticament, doncs:

Siguin els següents esdeveniments aleatoris:

W: guanyar, és dir, triar porta amb cotxe en la segona tria
G1: triar porta amb cabra en la primera tria
C1: triar porta amb cotxe en la primera tria

G1 i C1 són esdeveniments complementaris.

Probabilitat de G1 union C1 = P(G1 union C1) = 1 newline
Probabilitat de G1 intersection C1 = P(G1 intersection C1) = 0

Siguin les probabilitats
P(W) = Probabilitat de guanyar si canvia en segona opció
P(G1) = Probabilitat d’haver triat cabra en la primera opció (1/2)
P(Win | G1) = Probabilitat de guanyar si canvia en segona opció condicionat a haver triat cabra en la primera (1)
P(C1) = Probabilitat d’haver triat cotxe en la primera opció (1/2)
P(Win | C1) = Probabilitat de guanyar si canvia en segona opció condicionat a haver triat cotxe en la primera (1/2)

Aleshores:

Selecció_002

I Substituint:

(1/2) * (1/2) + 1 * (1/2) = 1/4 + 1/2 = 3/4 = 0.75

Per tant, l’estratègia correcta és canviar en la segona opció, ja que la probabilitat d’haver triat cotxe en la primera opció P(C1) és només de 1/2.

Aquest resultat xoca amb la intuïció. La majoria de la gent no veu que obrir la porta amb la cabra sigui motiu per canviar la porta triada. És un biaix psicològic relacionat amb l’efecte de dotació, o l’aversió a la pèrdua. Un cop el concursant “ha comprat” la primera porta, li atribueix més valor que el que realment pot tenir

Un llibre molt interessant (i llarg) que parla, d’entre moltes altres coses, d’aquest efecte és “Thinking, fast and slow” del premi Nobel, psicòleg i economista Daniel Kahneman, que amb Amos Tversky, va desenvolupar la denominada teoria de les perspectives (prospect theory), segons la qual els individus prenen decisions, en entorns d’incertesa, que s’aparten dels principis bàsics de la probabilitat.

El cas és que quan vaig llegir el problema per primer cop vaig caure de quatre potes al biaix cognitiu i la resposta ràpida que em va sortir era equivocada.

Ferit en l’orgull i com que els apunts de matemàtica em quedaven lluny vaig optar per solucionar el problema amb força bruta: Vaig escriure un programa en Python per repetir la versió modificada de l’experiment de Monty Hall tants cops com volgués, de forma que estimaria la probabilitat a partir de la freqüència dels resultats.

No cal dir que l’experiment confirma la teoria.

Es poden trobar molt bones explicacions teòriques del problema de Monty Hall a Internet i aquí n’he reproduït una adaptant-la al problema plantejat al MOOC.

Vet aquí el codi del simulador. Els casos de prova es poden ajustar amb la variable num_experiments (per defecte a 100.000)

No té truc: he definit una classe MontyHall que simula l’experiment al constructor que a mida que va progressant ajusta propietats. La classe té mètodes per consultar els valors de les propietats.

El bloc principal no és més que la repetició de l’experiment tants cops com digui num_experiments. A cada iteració acumula els valors. Finalment, calcula les probabilitats i mostra els resultats.

from random import *

class MontyHall():
    rand = None
    door = []
    first_selection = 0
    door_goat = 0
    new_user_selection = 0
    has_changed = 0
    has_won = 0
    
    def __init__(self):
        self.door = ["Car", "Car", "Car", "Car"]
    
        self.rand = Random()
        D1 = self.rand.randint(1,4)
        D2 = self.rand.randint(1,4)
		
        while( D1 == D2):
            D2 = self.rand.randint(1,4)
			
        self.door[D1-1] = "Goat"
        self.door[D2-1] = "Goat"

        #print "---------------------------"
        #print self.door

        # first user selection
        self.first_selection = self.rand.randint(1,4)
        #print "User selects door %d" % self.first_selection 

        # monty halls shows a goat
        for i in range(1,5):
            if (self.door[i-1] == "Goat") and (i != self.first_selection):
                self.door_goat = i
                break;

        #print "Monty Hall shows goat on door %d" % self.door_goat

                
        # user selects new door
        self.new_user_selection = self.rand.randint(1,4)
        while(self.new_user_selection == self.door_goat):
            self.new_user_selection = self.rand.randint(1,4)

        # has changed?
        if (self.new_user_selection != self.first_selection):
            self.has_changed = 1
            #print "User has changed from door %d to door %d" % (self.first_selection, self.new_user_selection)
        #else:
            #print "User has not changed and remains on door %d" % self.first_selection


        # User wins?
        #print "In door %d got a %s " % (self.new_user_selection, self.door[self.new_user_selection-1]) 
        if (self.door[self.new_user_selection-1] == "Car"):
            self.has_won = 1
            #print "User wins!"
        #else:
            #print "User loses!"

    def get_has_won(self):
        return self.has_won

    def get_has_changed(self):
        return self.has_changed;

    def show_new_user_selection(self):
        print self.new_user_selection

    def show_goat_door(self):
        print self.door_goat

    def show_first_selection(self):
        print self.first_selection
		
    def show(self):
        print self.door
		
# ---- main ----
num_experiments = 100000

for j in range(0, 10):

    count_changes = 0.0
    count_no_change_won = 0.0
    count_change_won = 0.0

    for i in range(1,num_experiments + 1):
        montyHall = MontyHall()
        count_changes = count_changes + montyHall.get_has_changed()
        if montyHall.get_has_changed() == 1:
            count_change_won = count_change_won + montyHall.get_has_won()
        else:
            count_no_change_won = count_no_change_won + montyHall.get_has_won()

    print "---------------------------"
    print "Totals:"
    print "Num. experiments: %d" % num_experiments
    print "Num changes: %d" % count_changes
    print "Num no changes: %d" % (num_experiments - count_changes)
    print "Num changes won: %d" % count_change_won
    print "Num no changes won: %d" % count_no_change_won
    print "Num changes won/Num changes = %f" % (count_change_won / count_changes)
    print "Num no changes won/Num no changes = %f" % (count_no_change_won / (num_experiments - count_changes))

Un bon experiment per a noies i nois de batxillerat.

El codi es pot descarregar del meu github: https://github.com/abaranguer/montyhall.