Programa para simular o Paradoxo do aniversário – python python-3.x matemática

Pergunta:


Em teoria das probabilidades, o paradoxo do aniversário afirma que dado um grupo de 23 (ou mais) pessoas escolhidas aleatoriamente, a chance de que duas pessoas terão a mesma data de aniversário é de mais de 50%. Para 57 ou mais pessoas, a probabilidade é maior do que 99%, entretanto, ela não pode ser exatamente 100% exceto que se tenha pelo menos 367 pessoas.

Escreva um programa que recebe um número n de pessoas e um número x de repetições e sorteia listas com datas de aniversário, e verifica se existe alguma data coincidente. Para cada loop deve-se re-sortear as listas, e para cada lista onde há casos coincidentes deve-se acrescentar 1 ao número de casos favoráveis. Depois de rodados os x loops de a porcentegem de vezes em que houve aniversários coincidentes.

Detalhe: Use compressão de listas para gerar as datas de aniversário

Tentativa de solução:

import random

datas =[x for x in range(1,366)]
#print(datas)


n = int(input("Digite o número de pessoas: "))
x = int(input("Digite o número de repetições: "))
datas_sorteadas = []
favoraveis = 0
for i in range(x):
    for i in range(n):
        datas_sorteadas.append(random.choice(datas))
        print(datas_sorteadas)

    for data in datas_sorteadas:
        if datas_sorteadas.count(data)>=2:
            favoraveis +=1
    datas_sorteadas = []
    datas_sorteadas.append(random.choice(datas))
    print(datas_sorteadas)

print("Casos Favoráveis: ", favoraveis)

print("n*x",n*x)
print("Percentual: ", (favoraveis/(n*x)))
#print(datas_sorteadas)

O programa está rodando sem erros mas desconfio que não está correto. Os resultados não condizem com a teoria. Alguma ideia de como corrigir?

Autor da pergunta Ed S

Miguel

Pela descrição do problema, creio estás a fazer algumas coisas escusadas, é mais simples do que parece.

O que é o paradoxo/problema do aniversário?

Video explicativo PT

Para simular isto podemos fazer assim:

  1. Receber como input o número de pessoas (num_p) e número de testes/repetições (num_loops) a fazer;
  2. Em cada teste geramos uma lista com num_p (número de pessoas) inteiros aleatórios, cada um poderá ter um valor entre 1 e 365 para simular o dia de aniversário de cada pessoa. Ex: em um teste com 6 pessoas poderemos obter [4, 144, 233, 98, 144, 43];
  3. Verificar se na lista gerada existe algum valor que ocorra mais do que uma vez nessa mesma lista, neste caso faço uso de any() e count(). Ex: [4, 144, 233, 98, 144, 43] (aniversários de 6 pessoas), neste caso 144 repete-se, ou seja, duas pessoas têm o mesmo dia de aniversário;
  4. Caso o ponto acima (3) se verifique é porque temos pelo menos 1 valor que se repete, aí incrementamos a nossa variável favoraveis, e no final dos testes calcular a percentagem de favoraveis em num_loops (número de testes).

Código:

import random

num_p = int(input("Digite o número de pessoas: "))
num_loops = int(input("Digite o número de repetições: ")) # num de testes
favoraveis = 0
for _ in range(num_loops):
    ani_dates = [random.randint(1, 366) for _ in range(num_p)] # sortear nova lista de datas (dias) de aniversario
    if(any(ani_dates.count(i) > 1 for i in ani_dates)): # verificar se existe a mesma data (valor) mais do que uma vez na lista
        favoraveis += 1

probs_perc = (favoraveis/num_loops)*100
print('Em {} pessoas e {} testes deram-se {} vezes em que pelo menos duas pessoas fazem anos no mesmo dia, percentagem: {}%'.format(num_p, num_loops, favoraveis, probs_perc))
# Em 23 pessoas e 1000 testes deram-se 504 vezes em que pelo menos duas pessoas fazem anos no mesmo dia, percentagem: 50.4%
# Em 57 pessoas e 1000 testes deram-se 993 vezes em que pelo menos duas pessoas fazem anos no mesmo dia, percentagem: 99.3%

DEMONSTRAÇÃO

Edição

Depois de rever esta resposta e realizar alguns testes notei que conseguimos uma melhor performance se fizermos uso de set() e da sua característica de não armazenar valores duplicados, assim podemos simplesmente verificar se comprimento do set é diferente (menor) do que o número de pessoas (num_p), se for é porque houveram valores duplicados, e tivemos pelo menos duas pessoas a fazer anos no mesmo dia (favoraveis += 1):

import random

num_p = int(input("Digite o número de pessoas: "))
num_loops = int(input("Digite o número de repetições: ")) # num de testes
favoraveis = 0
for _ in range(num_loops):
    ani_dates = {random.randint(1, 366) for _ in range(num_p)} # sortear novo set de datas (dias) de aniversario
    if(len(ani_dates) != num_p): # se o comprimento do set for diferente do num de pessoas
        favoraveis += 1

probs_perc = (favoraveis/num_loops)*100
print('Em {} pessoas e {} testes deram-se {} vezes em que pelo menos duas pessoas fazem anos no mesmo dia, percentagem: {}%'.format(num_p, num_loops, favoraveis, probs_perc))
# Em 23 pessoas e 1000 testes deram-se 506 vezes em que pelo menos duas pessoas fazem anos no mesmo dia, percentagem: 50.6%

DEMONSTRAÇÃO

A equação do aumento exponencial da probabilidade pode ser vista aqui, e eu ao testar essa mesma equação em python também fiz o gráfico.

Não tem haver com a pergunta mas aqui deixo o código para fazer esse gráfico:

import matplotlib.pyplot as plt

def birthday_probs(x):
    p = (1.0/365)**x
    for i in range((366-x),366):
        p *= i
    return 1-p

plt.plot([birthday_probs(i)*100 for i in range(366)])
plt.xlabel("Num de pessoas")
plt.ylabel("Probabilidades de partilha de dia de aniversário")
plt.ylim(ymin=0)
plt.xlim(xmin=0, xmax=80)
plt.show()

inserir a descrição da imagem aqui

Este link pode te ajudar:
Wikipedia: Paradoxo do Aniversário

Basicamente o código de probabilidades é:

def birthday(x):
    p = (1.0/365)**x
    for i in range((366-x),366):
        p *= i
    return 1-p

Fonte

Related Posts:

Qual a diferença entre AppCompatActivity e Activity? – android android-activity
Pergunta: Qual a diferença da AppCompatActivity para Activity ? A partir de qual versão a AppCompatActivity foi adicionada ao Android? Autor da pergunta Luhhh A diferença reside ...
Como abreviar palavras em PHP? – php string
Pergunta: Possuo informações comuns como nome de pessoas e endereços, e preciso que elas contenham no máximo 30 caracteres sem cortar palavras. Exemplo: 'Avenida Natalino João Brescansin' ...
Qual é a finalidade de um parêntese vazio numa declaração Lambda? – c# expressões-lambda característica-linguagem
Pergunta: Criei um exemplo de uma declaração Lambda sem argumentos, entretanto, estou com duvidas referente a omissão do parêntese vazio () na declaração. Veja o exemplo: class ...
Boas práticas para URI em API RESTful – api rest restful
Pergunta: Estou com dúvida em relação às URIs de alguns recursos da api que estou desenvolvendo. Tenho os recursos projetos e atividades com relação 1-N, ...
Dúvidas sobre a integração do MySQL com Java – java mysql netbeans
Pergunta: Estou criando um sistema no NetBeans, utilizando a linguagem Java e o banco de dados MySQL. Escrevi o seguinte código para realizar a conexão ...
Qual é a finalidade da pasta Model do framework Inphinit? – php inphinit
Pergunta: No Inphinit micro-framework existe a pasta Model que fica dentro da pasta application, e nela é onde ficam as classes, mas eu estou muito ...
Uso do ‘@’ em variáveis – javascript typescript coffeescript
Pergunta: Vejo em algumas linguagens que compilam para javascript, como TypeScript e CoffeeScript, o uso do @ em variáveis, como também, casos em que o ...
Qual tamanho máximo um arquivo JSON pode ter? – json arquivo
Pergunta: Vou dar um exemplo para conseguir explicar minha duvida: Preciso recuperar informação de imagens vindas de uma API, esse banco de imagens me retorna JSON's ...
O que é Teste de Regressão? – terminologia engenharia-de-software testes
Pergunta: Na matéria de Teste de Software o professor abordou um termo chamado Teste de Regressão, isto dentro da disciplina de teste de software. Sendo ...
O que é um construtor da linguagem? – php característica-linguagem
Pergunta: Em PHP, já li e ouvi várias vezes a respeito dos Construtores da Linguagem. Os casos que sempre ouvi falar deles foi em casos ...
Função intrínseca para converter numérico para string – cobol
Pergunta: Estou a tentar saber se existe alguma função intrínseca do COBOL para converter um data numérico para string sem precisar usar a cláusula REDEFINES: ( ...
Porque usar implements? – java android
Pergunta: Qual a diferença entre usar btn.setOnClickListener(new OnClickListener() { e public class MainActivity extends Activity implements OnClickListener{ Estive fazendo um curso de Android e meu professor falou que ...
O que é XHTML e quando deve ser usado? – html xml xhtml
Pergunta: O que eu sei é que o XHTML precisa ser XML válido. Isso implica, por exemplo, que todas as tags precisam ser fechadas. Por ...
Uma placa aceleradora de vídeo pode melhorar o desempenho não-gráfico? [fechada] – desempenho
Pergunta: Para desenvolver em Ruby on Rails, eu utilizo aqui uma máquina virtual do VirtualBox com Ubuntu Server 14.04 sem interface gráfica instalada. Recentemente descobri uma ...
Concat() VS Union() – c# .net
Pergunta: Qual a diferença entre Concat() e Union() ? Quando usar Concat() e quando usar Union() ? Somente pode ser usado em list ? ...

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *