Monty Hall e i flussi d’informazione
Nello studio di un sistema che genera imprevedibilità si definiscono delle probabilità da associare agli eventi o risultati possibili in base all’informazione che si ha in un dato momento.
Bisogna sempre tener conto che un’ulteriore informazione potrebbe implicare l’aggiornamento delle probabilità già calcolate. Se, per esempio, inizialmente pensiamo che tutte le possibilità siano equivalenti e simmetriche, allora la probabilità che si realizzi un loro sottoinsieme può essere definita mediante la nota formula casi favorevoli/casi possibili. Se, in un secondo tempo, una fonte esterna ci rivela delle informazioni in più, la probabilità dev’essere aggiornata mediante la formula di Bayes. La stessa cosa si deve fare se, agendo sul sistema, otteniamo dei risultati che rivelano informazione.
In questo articolo ci concentriamo sulla direzione di questi flussi informativi, mostrando come medesimi risultati o configurazioni possono dare origine a probabilità diverse di eventi futuri a seconda di come tali configurazioni o risultati siano stati ottenuti.
In pratica analizziamo tre modelli di gioco:
- Il problema Monty Hall classico
- Una variante del problema Monty Hall
- Una semplificazione del gioco “Affari Tuoi”
In tutti questi giochi il concorrente inizialmente compie una scelta in una situazione di scarsa informazione, poi nel corso del gioco egli ottiene delle informazioni e gli viene proposto di cambiare la sua scelta iniziale.
Proprio in riferimento al gioco molto conosciuto “Affari tuoi”, si dimostra che il cambio di pacco proposto dal “Dottore” risulta essere SEMPRE ininfluente ai fini della vittoria. In particolare, lo è anche quando si realizza una notevole disparità tra pacchi rossi e blu in gioco. Questo aspetto, ad alcuni, sembra incredibile, soprattutto alla luce del problema Monty Hall classico, nel quale il cambio conviene sempre, ma ciò avviene perché non si distingue il tipo di informazione che i giochi offrono nei due casi.
Il problema Monty Hall classico

Il problema Monty Hall è un celebre rompicapo di probabilità basato su un gioco televisivo. Il concorrente sceglie una porta su tre, dietro una delle quali c’è un’auto (premio) e dietro le altre due delle capre. Dopo la scelta, il conduttore (che sa cosa si nasconde dietro ogni porta) apre una delle porte rimanenti, mostrando sempre una capra, e offre la possibilità di cambiare la scelta. Sorprendentemente, passare alla porta rimanente aumenta le probabilità di vincere l’auto al 66,7% (2/3), contro solo il 33,3% (1/3) se si mantiene la scelta iniziale.
Dimostrazione




Osservazioni
L’informazione proviene dal conduttore che fa un’eliminazione con un criterio ben preciso consistente nell’aprire la porta in cui vi è sicuramente una capra. La porta che rimane, oltre a quella scelta dal concorrente, è frutto di una selezione che la rende, intuitivamente parlando, “speciale”.
Esperimento
Il seguente codice realizza 100.000 giocate in cui un concorrente (strategia 2) decide sempre di cambiare e un altro (strategia 1) decide di non cambiare mai.
import random
def simulate_monty_hall(n_simulations=100000):
# Inizializziamo i contatori per le vittorie per ciascuna strategia
wins_stay = 0 # Strategia: mantenere la scelta iniziale
wins_switch = 0 # Strategia: cambiare scelta
# Definiamo le porte come 0, 1, 2
doors = [0, 1, 2]
for _ in range(n_simulations):
# Distribuzione casuale del premio (auto) dietro una porta
prize = random.choice(doors)
# Il concorrente sceglie una porta a caso
choice = random.choice(doors)
# Il conduttore, che conosce la posizione dell'auto, deve aprire una porta
# che NON sia quella scelta dal concorrente e che contenga una capra.
# Calcoliamo l'insieme delle porte ammissibili per l'apertura.
possible_doors = [d for d in doors if d != choice and d != prize]
# Se il concorrente ha scelto la porta con l'auto (C1), entrambe le altre porte hanno una capra:
# il conduttore sceglie a caso tra le due.
# Se il concorrente ha scelto una porta con la capra (C2 o C3), l'unica porta ammissibile è quella
# che non contiene l'auto.
host_open = random.choice(possible_doors)
# La porta rimanente (non scelta dal concorrente e non aperta dal conduttore) è quella a cui si potrebbe cambiare
remaining = [d for d in doors if d != choice and d != host_open][0]
# Strategia 1: il concorrente mantiene la porta iniziale.
if choice == prize:
wins_stay += 1
# Strategia 2: il concorrente cambia alla porta rimanente.
if remaining == prize:
wins_switch += 1
return wins_stay, wins_switch
# Eseguiamo la simulazione per un gran numero di giocate
n_simulations = 100000
wins_stay, wins_switch = simulate_monty_hall(n_simulations)
# Visualizzazione dei risultati
print("Numero di giocate:", n_simulations)
print("Vittorie con la strategia 'resta': {} ({:.2f}%)".format(wins_stay, wins_stay / n_simulations * 100))
print("Vittorie con la strategia 'cambia': {} ({:.2f}%)".format(wins_switch, wins_switch / n_simulations * 100))
OUTPUT
Numero di giocate: 100000
Vittorie con la strategia ‘resta’: 33041 (33.04%) circa 1/3
Vittorie con la strategia ‘cambia’: 66959 (66.96%) circa 2/3
Variante del problema Monty Hall

In questa variante, il concorrente sceglie una porta tra le tre. Il conduttore non conosce la posizione del premio e sceglie a caso una delle porte non selezionate. Se dietro la porta scelta c’è una capra, il gioco continua e il concorrente può decidere se cambiare. Se invece viene rivelata l’auto, il gioco viene annullato e si riparte da capo.
In questo caso il cambio è ininfluente ai fini della vittoria benché la configurazione sia la stessa di quella del caso classico.
Dimostrazione




Osservazioni
L’informazione, questa volta, giunge grazie alla selezione casuale. La probabilità iniziale di 1/3 assegnata alla porta scelta dal concorrente dev’essere aggiornata sulla base delle informazioni che il sistema fornisce. Se il conduttore aprendo una porta trova casualmente una capra, vuol dire che la probabilità iniziale di 1/3 assegnata alla scelta del concorrente è stata sottostimata. Ora, si sa che è molto più probabile rispetto a prima che dietro alla sua porta ci sia l’auto. Infatti, tale probabilità sale a 1/2 e sarà uguale a quella dell’altra porta. Un altro modo di vedere la cosa è quello secondo cui qualsiasi selezione casuale fatta sul sistema non sbilancia le probabilità in gioco, la distribuzione rimane uniforme se lo era all’inizio, esattamente come un campione statistico scelto casualmente risulta rappresentativo di una popolazione più ampia.
Esperimento
Il seguente codice realizza 100.000 giocate in cui un concorrente (strategia 2) decide sempre di cambiare e un altro (strategia 1) decide di non cambiare mai. Vengono eliminate le giocate in cui il conduttore per caso trova l’auto.
import random
def simulate_variant(n_simulations=100000):
wins_stay = 0 # Vittorie mantenendo la scelta iniziale
wins_switch = 0 # Vittorie cambiando scelta
valid_games = 0 # Numero di giocate valide (dove il conduttore non rivela l'auto)
doors = [0, 1, 2]
for _ in range(n_simulations):
# Distribuzione casuale del premio: auto dietro una porta
prize = random.choice(doors)
# Il concorrente sceglie una porta a caso
choice = random.choice(doors)
# Il conduttore apre a caso una delle porte non scelte dal concorrente
available_doors = [d for d in doors if d != choice]
host_open = random.choice(available_doors)
# Se il conduttore rivela l'auto, escludiamo questa giocata dalla statistica
if host_open == prize:
continue
# La giocata è valida, incrementiamo il contatore
valid_games += 1
# La porta rimanente (non scelta e non aperta)
remaining = [d for d in doors if d != choice and d != host_open][0]
# Strategia 1: mantieni la scelta iniziale
if choice == prize:
wins_stay += 1
# Strategia 2: cambia scelta passando alla porta rimanente
if remaining == prize:
wins_switch += 1
return wins_stay, wins_switch, valid_games
# Eseguiamo la simulazione per un gran numero di giocate
n_simulations = 100000
wins_stay, wins_switch, valid_games = simulate_variant(n_simulations)
# Visualizziamo i risultati
print("Numero di giocate valide:", valid_games)
if valid_games > 0:
print("Vittorie con la strategia 'resta': {} ({:.2f}%)".format(wins_stay, wins_stay / valid_games * 100))
print("Vittorie con la strategia 'cambia': {} ({:.2f}%)".format(wins_switch, wins_switch / valid_games * 100))
else:
print("Nessuna giocata valida per la simulazione.")
OUTPUT
Numero di giocate valide: 66661
Vittorie con la strategia ‘resta’: 33512 (50.27%) circa 1/2
Vittorie con la strategia ‘cambia’: 33149 (49.73%) circa 1/2
Semplificazione del gioco “Affari Tuoi”

Ci sono inzialmente 20 pacchi di cui 10 rossi (vincenti) e 10 blu (perdenti). Il concorrente ne sceglie uno. Dopo una successione di estrazioni casuali che eliminano 15 pacchi, ne restano 5 compreso quello scelto dal concorrente all’inizio.
Se casualmente ci si trova nella configurazione: 4 pacchi rossi e 1 pacco blu, conviene al concorrente cambiare il pacco?
Non cambia nulla!
Per le ragioni già discusse nel contesto della variante del problema Monty Hall la risposta dev’essere negativa, in quanto la probabilità iniziale di 1/2 di avere il pacco rosso dev’essere aggiornata in base a ciò che il gioco ci dice. Poiché ci sono 4 pacchi rossi su 5 totali in gioco, significa che la probabilità iniziale di 1/2 è stata sottostimata. Ora dev’essere aggiornata e portata a 4/5. Ogni pacco in gioco ora ha la stessa probabilità di 4/5 di essere rosso, in quanto la selezione casuale non ha alterato l’uniformità della distribuzione di origine.
Esperimento
Il seguente codice realizza 1 milione di giocate in cui un concorrente decide di cambiare e un altro decide di non cambiare mai. Vengono eliminate le giocate in cui la configurazione è diversa da quella con 4 pacchi rossi e 1 pacco blu.
import random
def simulate_game():
# Crea la lista dei 20 pacchi: 10 rossi ('R') e 10 blu ('B')
pacchi = ['R'] * 10 + ['B'] * 10
random.shuffle(pacchi) # Mischia casualmente i pacchi
# Il concorrente estrae un pacco, che diventa il suo pacco iniziale
concorrente_pacco = pacchi.pop()
# Copia i pacchi rimanenti
restanti_pacchi = pacchi.copy()
# Rimuove 15 pacchi casualmente dalla lista dei pacchi rimanenti
rimuovi = random.sample(restanti_pacchi, 15)
for r in rimuovi:
restanti_pacchi.remove(r)
# I 5 pacchi finali sono il pacco iniziale + i 4 pacchi rimanenti
cinque_pacchi = [concorrente_pacco] + restanti_pacchi
return cinque_pacchi, concorrente_pacco, restanti_pacchi
# Parametri di simulazione
rounds = 1000000 # Si eseguono molti round per ottenere abbastanza casi filtrati
cases = 0 # Contatore dei casi in cui i 5 pacchi sono 4 rossi e 1 blu
strat1_wins = 0 # Vittorie per la strategia "cambia sempre"
strat2_wins = 0 # Vittorie per la strategia "non cambiare mai"
for _ in range(rounds):
cinque_pacchi, concorrente_pacco, restanti_pacchi = simulate_game()
# Si considerano solo i casi in cui i pacchi finali contengono esattamente 4 rossi e 1 blu
if cinque_pacchi.count('R') == 4 and cinque_pacchi.count('B') == 1:
cases += 1
# Strategia 1: cambia sempre il pacco iniziale
nuovo_pacco = random.choice(restanti_pacchi)
if nuovo_pacco == 'R':
strat1_wins += 1
# Strategia 2: non cambiare mai il pacco iniziale
if concorrente_pacco == 'R':
strat2_wins += 1
# Mostra i risultati solo se sono stati trovati dei casi validi
print(f"Casi totali (4 rossi, 1 blu): {cases}")
if cases > 0:
print(f"Strategia 1 (cambia sempre): {strat1_wins/cases*100:.2f}% vittorie")
print(f"Strategia 2 (non cambiare mai): {strat2_wins/cases*100:.2f}% vittorie")
OUTPUT
Casi totali (4 rossi, 1 blu): 135530
Strategia 1 (cambia sempre): 80.00% vittorie (circa 4/5)
Strategia 2 (non cambiare mai): 80.06% vittorie (circa 4/5)
Autore: Alvise Giubelli
HumAI.it