For én tilfeldig valgt person antar vi at alle datoer i året (365) er like sannsynlige å ha som bursdag. Vi skal trekke $n$ personer tilfeldig og regne ut sannsynligheten for at minst to av disse har bursdag på samme dag. Under de gitte antagelsene kan du regne ut dette "for hånd", men her skal vi estimere denne sannsynligheten ved å kjøre en simulering.
I hver iterasjon i simuleringen (for-løkka) trekker vi tilfeldige tall mellom 1 og 365 for de $n$ personene. Dersom to eller flere personer ble tildelt det samme tallet, registrerer vi en "suksess" ($x = 1$). Dersom alle de $n$ personene fikk tildelt ulike bursdager, registrerer vi en "fiasko" ($x = 0$). Til slutt teller vi opp alle suksesser og deler på antall simuleringer for å få et estimat på sannsynligheten for at minst to personer i en gruppe på $n$ mennesker har bursdag på samme dag.
import numpy as np
np.random.choice(5,3) # for å trekke tilfeldige tall, 5 betyr at vi trekker fra tallene (0,1,2,3,4), og 3 at vi trekker tre tall
np.unique([1,2,4,5,2,4,2]) # returnerer kun de unike tallene i denne arrayen
Her kan man regne eksakt - og det er lagt opp til det i oppgaven - men du kan også simulere. Slik gjøres simuleringen.
n_sim = 100000 # Antall simuleringer du vil gjøre
n = 23 # Antall personer som skal velges ut
dager = 365
x = np.zeros(n_sim) # initialiserer x-vektor med bare 0-eller
for i in range(n_sim):
bursdager = np.random.choice(dager, n) # trekker tilfeldige datoer
if len(np.unique(bursdager)) < n: # Dersom det ikke er like mange unike bursdager som det er personer
x[i] = 1
estimat = sum(x)/n_sim
print(estimat)
Oppdatering 29 AUG: Den følgende simuleringen er gjennomført for mange ulike n. Resultatene fra simuleringen kan du bruke for å løse STACK-oppgaven uten tilgang til huben.
n_sim = 100000 # Antall simuleringer du vil gjøre
dager = 365
# Vi vil prøve oss frem med mange n
n_values = range(10, 51)
# Her vil vi lagre resultat (sannsynlighet for minst to har samme bursdag) for hver n
results = {}
for n in n_values:
x = np.zeros(n_sim) # initialiserer x-vektor med bare 0-eller
for i in range(n_sim):
bursdager = np.random.choice(dager, n) # trekker tilfeldige datoer
if len(np.unique(bursdager)) < n: # Dersom det ikke er like mange unike bursdager som det er personer
x[i] = 1
estimat = sum(x) / n_sim
results[n] = estimat
# Skriv ut resultater for ulike n
print("n\tSannsynlighet")
print("-" * 20)
for n, estimat in results.items():
print(f"{n}\t{estimat:.6f}")
n Sannsynlighet -------------------- 10 0.118420 11 0.141690 12 0.166710 13 0.195740 14 0.223560 15 0.251970 16 0.283420 17 0.316280 18 0.346750 19 0.380470 20 0.412580 21 0.443310 22 0.472830 23 0.506100 24 0.538750 25 0.567560 26 0.595950 27 0.623940 28 0.653820 29 0.678590 30 0.707830 31 0.728880 32 0.755250 33 0.773200 34 0.797740 35 0.811650 36 0.832500 37 0.847380 38 0.864500 39 0.879830 40 0.891230 41 0.903650 42 0.914210 43 0.923580 44 0.933390 45 0.939990 46 0.947250 47 0.955790 48 0.960350 49 0.965530 50 0.968850
I simulering 1 antok vi at for en tilfeldig valgt person var alle dager i året like sannsynlige for å ha bursdag (1/365). I realiteten vet vi at noen måneder er mer "populære" enn andre. Vi har hentet data på antall fødsler i Norge per måned i 2001 (ikke et skuddår), fra SSB: https://www.ssb.no/statbank/table/05531/. Disse dataene bruker vi til å anslå sannsynlighet for å være født i de ulike månedene. Vi antar at alle dager innenfor en gitt måned er like sannsynlige.
antall_fødsler = np.array([4959, 4495, 4958, 5009, 5018, 4955, 4919, 4852, 4742, 4555, 4153, 4081])
andel_fødsler = antall_fødsler/sum(antall_fødsler)
mnd_dager = [31,28,31,30,31,30,31,31,30,31,30,31]
daglig_prob = [andel_fødsler[0]/mnd_dager[0]]*mnd_dager[0] # initialisere
for i in range(1,12):
daglig_prob = daglig_prob + [andel_fødsler[i]/mnd_dager[i]]*mnd_dager[i]
# set(daglig_prob) # se på daglige sannsynligheter i hver mnd
# 1/365 # sammenligne med antagelsen i simulering 1
print(np.unique(daglig_prob)) # har fått 12 unike sannsynligheter, en for dagene i hver måned - men husk at daglig_prob har 365 elementer - og det er 12 unike verdier
[0.00232195 0.00244168 0.00259164 0.00276062 0.00278797 0.00279874 0.00282093 0.0028215 0.00283152 0.00285507 0.0029132 0.00294495]
n_sim = 100000 # Antall simuleringer du vil gjøre
n = 50 # Antall personer som skal velges ut
dager = 365
y = np.zeros(n_sim) # initialiserer y-vektor med bare 0-eller
for i in range(n_sim):
bursdager = np.random.choice(dager, n, daglig_prob) # trekker tilfeldige datoer
if len(np.unique(bursdager)) < n: # Dersom det ikke er like mange unike bursdager som det er personer
y[i] = 1
estimat = sum(y)/n_sim
print(estimat)
Oppdatering 29 AUG: Den følgende simuleringen er gjennomført for mange ulike n. Resultatene fra simuleringen kan du bruke for å løse STACK-oppgaven uten tilgang til huben.
n_sim = 100000 # Antall simuleringer du vil gjøre
dager = 365
# Vi vil prøve oss frem med mange n
n_values = range(15, 30)
# Her vil vi lagre resultat (sannsynlighet for minst to har samme bursdag) for hver n
results = {}
for n in n_values:
y = np.zeros(n_sim) # initialiserer y-vektor med bare 0-eller
for i in range(n_sim):
bursdager = np.random.choice(dager, n, daglig_prob) # trekker tilfeldige datoer
if len(np.unique(bursdager)) < n: # Dersom det ikke er like mange unike bursdager som det er personer
y[i] = 1
estimat = sum(y)/n_sim
results[n] = estimat
# Skriv ut resultater for ulike n
print("n\tSannsynlighet")
print("-" * 20)
for n, estimat in results.items():
print(f"{n}\t{estimat:.6f}")
n Sannsynlighet -------------------- 15 0.251210 16 0.282150 17 0.316310 18 0.342800 19 0.378690 20 0.409900 21 0.444470 22 0.478380 23 0.510650 24 0.537390 25 0.570040 26 0.596530 27 0.626510 28 0.652520 29 0.678260