Â
Imagem gerada por eu mesmo, usando Stable Diffusion.
O problema de Monty Hall, tambĂ©m conhecido por paradoxo de Monty Hall Ă© um problema matemĂĄtico e paradoxo que surgiu a partir de um concurso televisivo dos Estados Unidos chamado Letâs Make a Deal, exibido na dĂ©cada de 1970.
O jogo consistia no seguinte: Monty Hall, o apresentador, apresentava trĂȘs portas aos concorrentes. AtrĂĄs de uma delas estava um prĂȘmio (um carro) e, atrĂĄs das outras duas, dois bodes.
Â
Imagem retirada do google.
Qual Ă© a estratĂ©gia mais lĂłgica? Ficar com a porta escolhida inicialmente ou mudar de porta? Com qual das duas portas ainda fechadas o concorrente tem mais probabilidades de ganhar? Por quĂȘ?
Nota: copiei o trecho de introdução acima da wikipedia.
A computação Ă© uma ferramenta extremamente versĂĄtil e nos possibilita a representação de muitas coisas menos tangĂveis. O paradoxo, ou problema, de Monty Hall Ă© uma situação que gerou muita polĂȘmica quando surgiu. A princĂpio, a solução Ăłbvia, mas errada, Ă© que todas as portas tem a mesma probabilidade de conter um carro. Mas Ă© aĂ que muitas pessoas se enganam, e nĂŁo por culpa delas, a estatĂstica consegue ser exaustivamente cansativa e nĂłs humanos temos muita dificuldade de generalizar algumas situaçÔes.
A resposta mais correta para a pergunta da introdução é que a probabilidade de haver um carro na porta não escolhida é de 66.6%. Isso acontece porque a probabilidade de haver um carro nas duas portas, antes de Hall intervir no jogo é de 66.6%. O simples fato de Hall conhecer a porta correta e necessariamente escolher a errada interfere no jogo.
Nesse sentido, minha motivação com esse documento é de demonstrar que essa probabilidade faz todo o sentido pråtico com simulaçÔes computacionais.
Abaixo, determino uma função que simula perfeitamente o jogo que Hall realizava na tv. Coloquei um âextraâ, que me permite aumentar o nĂșmero de portas, mantendo a lĂłgica do jogo.
monty_hall <- function(portas = 1:3, trocar = TRUE){
# Determino a porta premiada antes do inĂcio da simulação.
porta_premiada <- sample(portas, 1)
# O computador escolhe uma das portas
porta_escolhida <- sample(portas, 1)
# Se o jogador nunca trocar de portas, o jogo pode acabar aqui mesmo.
if (trocar == FALSE) {
return(porta_escolhida == porta_premiada)
}
### A Intervenção de Hall
# Adiciono uma abordagem recursiva para permitir a simulação com mais de 3 portas.
# Seleciona as n portas que o jogador nĂŁo escolheu
portas_nao_selecionadas <- portas[!porta_escolhida == portas]
while (length(portas_nao_selecionadas) > 1) {
# Remove a porta nĂŁo premiada (se nenhuma for premiada, remove aleatorio)
# Uma consideração importante a ser feita é sobre a natureza da função sample().
# Caso a função seja usada da seguinte forma: sample(2, 1), o valor retornado não é 2!
if (porta_premiada %in% portas_nao_selecionadas) {
portas_nao_selecionadas_sem_porta_premiada <- portas_nao_selecionadas[portas_nao_selecionadas != porta_premiada]
# Como o valor acima pode assumir um numero inteiro, adiciono a lĂłgica abaixo
if(length(portas_nao_selecionadas_sem_porta_premiada) == 1) {
porta_a_ser_removida <- portas_nao_selecionadas_sem_porta_premiada
} else {
porta_a_ser_removida <- sample(portas_nao_selecionadas_sem_porta_premiada, 1, replace = FALSE)
}
portas_nao_selecionadas <- portas_nao_selecionadas[portas_nao_selecionadas != porta_a_ser_removida]
} else {
porta_a_ser_removida <- sample(portas_nao_selecionadas, 1, replace = FALSE)
portas_nao_selecionadas <- portas_nao_selecionadas[portas_nao_selecionadas != porta_a_ser_removida]
}
# Opção de trocar ou não de porta
if (trocar) {
# No caso de mais de uma porta, a troca é realizada todas as vezes, até o fim.
if (length(portas_nao_selecionadas) > 1) {
porta_escolhida <- sample(portas_nao_selecionadas, 1, replace = FALSE)
} else {
porta_escolhida <- portas_nao_selecionadas # Até sobrar uma
}
}
}
# Retorna verdadeiro para o caso de ganho do jogo e falso para perda.
return(porta_escolhida == porta_premiada)
}A tĂtulo de ilustração, minha função que simula o paradoxo de Monty Hall retorna apenas um valor, que indica se eu ganhei o carro ou nĂŁo. Dentro dessa função, determino se eu seguirei a estratĂ©gia de trocar ou nĂŁo de portas, e o nĂșmero de portas.
Um exemplo dessa simulação, rodando apenas uma vez, com 3 portas e trocando a porta escolhida após a intervenção de Hall é a seguinte:
## [1] FALSE
Nesse caso acima, como o retorno da função foi FALSE, eu não ganhei o carro :(
A função desenvolvida simula perfeitamente o problema de Monty Hall, a ideia que apresento aqui, Ă© de rodar essa situação dez mil de vezes, uma trocando a porta escolhida inicialmente, e outra mantendo a escolha inicial. Quantas vezes eu ganho o jogo mantendo a porta que escolhi no começo? Quantas vezes eu ganho trocando a porta sempre que possĂvel?
Observação: Isso sĂł Ă© possĂvel hoje em dia porque temos o computador e a programação de forma acessĂvel!
Abaixo, o código responsåvel por replicar a minha função 20.000 vezes, 10.000 vezes para cada caso.
nucleos <- detectCores(logical = FALSE)
cl <- makeCluster(nucleos, type = "FORK")
numero_de_vezes <- 10000
resultado_trocando_de_portas <- clusterApply(cl, rep(list(1:3), numero_de_vezes), monty_hall)
resultado_trocando_de_portas <- unlist(resultado_trocando_de_portas)
resultado_nao_trocando_de_portas <- clusterApply(cl, rep(list(1:3), numero_de_vezes), monty_hall, trocar = FALSE)
resultado_nao_trocando_de_portas <- unlist(resultado_nao_trocando_de_portas)
stopCluster(cl)Veja, que a ideia que utilizo Ă© de simplesmente captar o resultado de
cada jogo. Cada um desses resultados Ă© salvo em uma lista,
que Ă© um tipo de variĂĄvel no R. Por exemplo, o que meu computador gerou
para resultado_trocando_de_portas (100 de 10000) foi:
## [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [13] TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [37] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [73] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE
## [85] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [97] TRUE TRUE TRUE TRUE
Agora é simples, comparo nas duas situaçÔes quantas vezes eu ganhei o carro nas duas estratégias. Uma representação em gråfico de barras é a seguinte:
# Salvo em uma tabela so
tabela_trocar <- data.frame(resultado = resultado_trocando_de_portas, estrategia = rep("Trocar", numero_de_vezes))
tabela_sem_trocar <- data.frame(resultado = resultado_nao_trocando_de_portas, estrategia = rep("NĂŁo trocar", numero_de_vezes))
dados <- as.data.table(rbind(tabela_sem_trocar, tabela_trocar))
# Faço o cålculo dessa proporção, para cada estratégia
dados <- dados[, .(resultado = sum(resultado) / numero_de_vezes), estrategia]
ggplotly(
ggplot(dados, aes(resultado, estrategia)) +
geom_col(position = "dodge", fill = "steelblue") +
theme_classic() +
coord_flip() +
labs(y = "SimulaçÔes em que a estratégia foi:", x = "Proporção de vitórias, com relação ao total de jogos") +
scale_x_continuous(n.breaks = 15, limits = c(0, 1), labels = scales::label_percent()) +
theme(plot.caption = element_text(hjust=0.5))
)Ou seja, a estratégia de trocar de portas me faz ganhar o carro ~66.6% das vezes, enquanto não trocar me faz ganhar somente ~33.3%!
Caso eu aumente o nĂșmero de portas para 5, veja como essa estratĂ©gia fica ainda mais descarada.
nucleos <- detectCores(logical = FALSE)
cl <- makeCluster(nucleos, type = "FORK")
numero_de_vezes <- 10000
resultado_trocando_de_portas <- clusterApply(cl, rep(list(1:5), numero_de_vezes), monty_hall)
resultado_trocando_de_portas <- unlist(resultado_trocando_de_portas)
resultado_nao_trocando_de_portas <- clusterApply(cl, rep(list(1:5), numero_de_vezes), monty_hall, trocar = FALSE)
resultado_nao_trocando_de_portas <- unlist(resultado_nao_trocando_de_portas)
stopCluster(cl)
# Salvo em uma tabela so
tabela_trocar <- data.frame(resultado = resultado_trocando_de_portas, estrategia = rep("Trocar", numero_de_vezes))
tabela_sem_trocar <- data.frame(resultado = resultado_nao_trocando_de_portas, estrategia = rep("NĂŁo trocar", numero_de_vezes))
dados <- as.data.table(rbind(tabela_sem_trocar, tabela_trocar))
# Faço o cålculo dessa proporção, para cada estratégia
dados <- dados[, .(resultado = sum(resultado) / numero_de_vezes), estrategia]
ggplotly(
ggplot(dados, aes(resultado, estrategia)) +
geom_col(position = "dodge", fill = "steelblue") +
theme_classic() +
coord_flip() +
labs(y = "SimulaçÔes em que a estratégia foi:", x = "Proporção de vitórias, com relação ao total de jogos") +
scale_x_continuous(n.breaks = 15, limits = c(0, 1), labels = scales::label_percent()) +
theme(plot.caption = element_text(hjust=0.5))
)Em uma simulação com 5 portas, cada uma teria a mesma chance inicial de 20% de conter um carro, mas se, para cada vez que Hall fizer a pergunta de trocar ou nĂŁo de porta, o jogador decidir trocar, ele consegue ganhar 80% das vezes que troca sempre que possĂvel! Que absurdo nĂ©? Nada intuitivo isso.
E com 100 portas? A probabilidade do carro estar atrĂĄs de qualquer uma dessas seria de 1%. Se eu trocar absolutamente todas as vezes, o que acontece?
nucleos <- detectCores(logical = FALSE)
cl <- makeCluster(nucleos, type = "FORK")
numero_de_vezes <- 10000
resultado_trocando_de_portas <- clusterApply(cl, rep(list(1:100), numero_de_vezes), monty_hall)
resultado_trocando_de_portas <- unlist(resultado_trocando_de_portas)
resultado_nao_trocando_de_portas <- clusterApply(cl, rep(list(1:100), numero_de_vezes), monty_hall, trocar = FALSE)
resultado_nao_trocando_de_portas <- unlist(resultado_nao_trocando_de_portas)
stopCluster(cl)
# Salvo em uma tabela so
tabela_trocar <- data.frame(resultado = resultado_trocando_de_portas, estrategia = rep("Trocar", numero_de_vezes))
tabela_sem_trocar <- data.frame(resultado = resultado_nao_trocando_de_portas, estrategia = rep("NĂŁo trocar", numero_de_vezes))
dados <- as.data.table(rbind(tabela_sem_trocar, tabela_trocar))
# Faço o cålculo dessa proporção, para cada estratégia
dados <- dados[, .(resultado = sum(resultado) / numero_de_vezes), estrategia]
ggplotly(
ggplot(dados, aes(resultado, estrategia)) +
geom_col(position = "dodge", fill = "steelblue") +
theme_classic() +
coord_flip() +
labs(y = "SimulaçÔes em que a estratégia foi:", x = "Proporção de vitórias, com relação ao total de jogos") +
scale_x_continuous(n.breaks = 15, limits = c(0, 1), labels = scales::label_percent()) +
theme(plot.caption = element_text(hjust=0.5))
)Trocar de portas Ă© sempre a melhor estratĂ©gia possĂvel!
Espero que tenha gostado desse documento, e até uma próxima!