Il y a très exactement 5 ans, sur ce blog, je vous parlais du paradoxe de Monty Hall que je vous prouvais avec les mains. Comme tout paradoxe mathématique, il parait au premier abord quelque peu contrintuitif jusqu'à ce qu'on se penche vraiment sur le problème. Je vous propose de revenir sur ce problème et de le prouver de deux façons : une approche pratique à l'aide d'une simulation informatique pour vérifier ou infirmer notre intuition, et une approche mathématique un peu plus formelle à l'aide du théorème de Bayes.

Chèvre

L'énoncé

Le problème énoncé pour la première fois en 1975 est le suivant : un jeu télévisé met en scène 3 portes. Derrière deux d'entre elles se cachent une chèvre et derrière la troisième se cache une voiture, réparties au hasard. Le candidat (sauf s'il s'agit d'un véritable ami des bêtes) va donc tenter de deviner derrière quelle porte se cache la voiture pour tenter de la gagner. Le présentateur sait ce qui se trouve derrière chacune des portes et le jeu se déroule en plusieurs temps :

  • Le joueur choisit tout d'abord une porte au hasard
  • Sur les deux portes restantes, le présentateur en dévoile une derrière laquelle se trouve une des chèvres
  • Puis on demande alors au candidat s'il souhaite conserver son choix ou changer pour sélectionner l'autre porte

La question est alors la suivante : le joueur a-t-il intérêt à changer de porte ?

La première idée qui vient à l'esprit est que le choix est équiprobable et que, peu importe son choix, le joueur a 50% de chances de gagner. Mais est-ce aussi simple que ça ?

Simulation

Pour vérifier notre intuition, créons une simulation simple à l'aide d'un petit script simple en python. Ce script assez simple se déroule en 4 étapes principales :

  • On simule le placement de la voiture grace à \(repartirVoiture()\). Le choix est fait au hasard entre les 3 portes, avec une probabilité identique pour toutes les portes.
  • On simule le choix du candidat avec \(simulerChoixCandidat()\). Là, on peut faire un peu ce qu'on veut : rendre le choix aléatoire, choisir toujours la même porte ou s'en remettre aux astres si vous le voulez, ça ne changera pas le résultat.
  • On simule l'ouverture d'une porte derrière laquelle se trouve une chèvre avec \(ouvrirPorte()\). On considère que le présentateur sait ce qui se cache derrière chacune des portes, il ouvre donc la première porte derrière laquelle se trouve une chèvre. Mais on pourrait très bien choisir une des deux portes restantes aléatoirement également si on le voulait.
  • On simule le changement d'avis du candidat par \(changerChoix()\) le cas échéant

Ensuite, on compare tout simplement les résultats pour un grand nombre de candidats entre le choix initial et le changement de choix et on regarde les résultats. Voici donc les détails du code de la simulation :

import numpy as np

def repartirVoiture(n):
    '''Repartition aleatoire des voitures pour n emissions'''
    voitures = np.random.randint(0, 3, n)
    return voitures

def simulerChoixCandidat(n, mode='random'):
    '''Simulation des choix des candidats pour n emissions (soit aleatoire, soit toujours le meme)'''
    if mode is not 'random':
        choix = np.array([1]*n)
    else:
        choix = np.random.randint(0, 3, n)
    return choix

def ouvrirPorte(prix, choix):
    '''Ouverture d'une porte par le presentateur en fonction de la position de la voiture et du choix du candidat'''
    portesOuvertes = np.zeros(choix.shape)
    for i, x in enumerate(prix):
        for k in [0, 1, 2]:
            if k != x and k != choix[i]:
                portesOuvertes[i] = k
    return portesOuvertes

def changerChoix(choix, portesOuvertes):
    '''Le candidat decide de changer de choix apres l'ouverture de la porte par le presentateur'''
    secondChoix = np.zeros(choix.shape)
    for i, x in enumerate(portesOuvertes):
        for k in [0, 1, 2]:
            if k != x and k != choix[i]:
                secondChoix[i] = k
    return secondChoix

def afficherResultats(choixFinal, prix):
    '''Afficher les taux de gain en pourcentages'''
    mask = choixFinal == prix
    pc = mask.sum() / float(len(mask)) * 100
    return pc

n = 10000
choix          = simulerChoixCandidat(n)
prix           = repartirVoiture(n)
portesOuvertes = ouvrirPorte(prix, choix)
secondChoix    = changerChoix(choix, portesOuvertes)
print 'Reussite sans changement : %0.2f%%' % afficherResultats(choix, prix)
print 'Reussite avec changement : %0.2f%%' % afficherResultats(secondChoix, prix)

Quand on lance le script, il nous retourne les résultats suivants:

Reussite sans changement : 32.90%
Reussite avec changement : 67.10%

Contrairement à nos premières intuitions, il semblerait que les candidats qui choisissent de changer de porte soient plus chanceux que les autres : 67% de gagnants contre 33% pour ceux qui campent sur leurs positions ! Je vous l'accorde, c'est un peu contre-intuitif, mais ça n'est pas complètement aberrant. Essayons de comprendre pourquoi avec quelques équations...

Mise en équations

En fait, généralement, on part du principe que la voiture a autant de chance de se trouver derrière n'importe quelle porte puisqu'elle est répartie de façon aléatoire. Du coup, si l'on note \(P(V_i)\) la probabilité que la voiture se trouve derrière la porte \(i\), on a \(P(V_1) = P(V_2) = P(V_3) = \frac{1}{3}\). Jusque là, le raisonnement est vrai, du moins au début, pour le premier choix !

Cependant, on néglige un point particulièrement important : la suite des évènements nous apporte des informations supplémentaires sur le jeu. En effet, le présentateur, qui sait ce qui se trouve derrière les portes, ouvre délibérément une des deux portes restantes. Du coup, il nous apporte une information supplémentaire sur la porte qu'il n'a pas ouverte : s'il ne l'a pas ouverte, c'est qu'il y a plus de chances que la voiture se cache derrière. Par contre, il n'apporte aucune information sur la première porte choisie puisque de toute façon il ne peut pas l'ouvrir.

Du coup, admettons que nous ayons choisi la porte 1 et que le présentateur ouvre la porte 2. Alors \(P(V_1) = \frac{1}{3}\) reste inchangée par rapport au choix initial. La porte 2 est ouverte par le présentateur, du coup \(P(V_2) = 0\). Et enfin \(P(V_3) = 1 - P(V_2) - P(V_3) = \frac{2}{3}\) augmente du même coup.

Essayons de valider notre nouveau raisonnement mathématiquement à l'aide du théorème de Bayes. Pour rappel, son énoncé est le suivant :

Soit \(P(A|B)\), la probabilité de A sachant B et \(P(A)\) la probabilité de A. Alors,

\[P(A|B) = \frac{P(B|A)P(A)}{P(B)}\]

Utilisons d'appliquer ce théorème de Bayes à la résolution de notre petit problème. Comme tout à l'heure, au hasard, choisissons la porte 1. Puis, considérons que le présentateur, lui, nous montre une chèvre derrière la porte 2. Soit \(V_1\) l'évènement "la voiture se trouve derrière la porte 1" et \(C_2\) "le présentateur montre la chèvre derrière la porte 2". Alors, en utilisant la formule ci-dessus, on peut calculer \(P(V_1|C_2)\) la probabilité que la voiture soit derrière la porte 1 sachant que le présentateur ouvre la porte 2 :

\[P(V_1|C_2) = \frac{P(C_2|V_1)P(V_1)}{P(C_2)}\]

A ce point, il y a plusieurs subtilités :

  • Le présentateur, sachant que la voiture est derrière la porte 1 choisie par le candidat, peut ouvrir indifféremment la porte 2 ou la porte 3. On a donc \(P(C_2|V_1) = P(C_3|V_1) = \frac{1}{2}\)
  • \(P(V_1) = \frac{1}{3}\) car à la base, la voiture est répartie de manière équiprobable derrière l'une des 3 portes.
  • Le plus compliqué reste de calculer le dernier terme, ce que je vais tâcher de vous expliquer juste après.

Une astuce consiste à se rappeler que l'on peut décomposer le dénominateur comme suit : \(P(C_2) = P(C_2|V_1)P(V_1) + P(C_2|V_2)P(V_2) + P(C_2|V_3)P(V_3)\). En effet, la probabilité \(P(C_2)\) est la somme de chacune des probabilités conditionnelles multipliée par la probabilité de cette condition.

Or, \(P(V_1) = P(V_2) = P(V_3) = \frac{1}{3}\) car la voiture est encore une fois positionnée au hasard selon une loi uniforme.

Enfin, nous avons déjà déterminé que \(P(C_2|V_1) = \frac{1}{2}\). De même \(P(C_2|V_2) = 0\) car le présentateur ne va pas ouvrir la porte si la voiture se trouve derrière ! \(P(C_2|V_3) = 1\) car si le candidat choisit la première porte et que la voiture est derrière la troisième, le présentateur n'a d'autre choix que d'ouvrir la porte du milieu.

Du coup, on obtient :

\[P(V_1|C_2) = \frac{\frac{1}{2} \times \frac{1}{3}}{\frac{1}{2} \times \frac{1}{3} + 0 \times \frac{1}{3} + 1 \times \frac{1}{3}} = \frac{1}{3}\]

On a donc 33% de chance de gagner en campant sur nos positions originelles. On peut faire un calcul analogue pour \(P(V_3|C_2)\) et sans surprise on obtient :

\[P(V_3|C_2) = \frac{P(C_2|V_3)P(V_3)}{P(C_2)} = \frac{1 \times \frac{1}{3}}{\frac{1}{2} \times \frac{1}{3} + 0 \times \frac{1}{3} + 1 \times \frac{1}{3}} = \frac{2}{3}\]

Et tout ça colle bien avec notre simulation ! On retombe donc sur nos pieds.

Conclusion

On vient donc de voir comment une simple information donnée par le présentateur change totalement la donne et permet d'établir une stratégie gagnante. Attention, ça ne veut pas dire qu'en adoptant la stratégie adaptée vous gagnerez, mais vous maximisez vos chances de gagner. Et ces probabilités de gain peuvent se calculer relativement facilement à l'aide du théorème de Bayes qui est finalement un outil assez simple tant qu'on comprend les probabilités que l'on manipule et que l'on calcule. Alors à vos équations... Prêts ? Partez !