Samansett simulering i S2

programmering
s-matte
simulering
eksamensoppgåve
tips
Forfattar

Torodd F. Ottestad

Publisert

March 3, 2023

Simulering som verktøy 💪

Ein del problemstillingar kan vera ganske vanskelege å løysa ved rekning. Simulering kan hjelpa til å gjera denne type oppgåver mykje lettare å løysa. I dag ser me på ei oppgåve henta frå eksempelsettet til skriftleg eksamen etter ny læreplan i S2.

Ta gjerne ein kikk på dette innlegget om du treng oppfrisking i grunnleggande simulering med NumPy. Ellers er dokumentasjonen til NumPy ein fin stad å vera…

Oppgåva

På ein skule er det 323 jenter og 301 gutar. La \(X\) vera høgda til ei tilfeldig vald jente og \(Y\) vera høgda til ein tilfeldig vald gut. Me går ut frå at \(X\) og \(Y\) er normalfordelt med \(\mu_x=168 cm\), \(\mu_y=180 cm\), \(\sigma_x = 6 cm\) og \(\sigma_y = 8 cm\).

Lag eit program som du kan bruka til å simulera sannsynet for at ein tilfeldig vald elev er høgare enn 175 cm. Bestem dette sannsynet.

(UDIR - Eksempelsett eksamen S2-V23 oppgåve 6, del 2)

🧐 Me må altså både bestemma om det er gut eller jente me har trekt i tillegg til å finna høgda på eleven. Krevande for hand/analytisk men ikkje så aller verst å finna ut av ved simulering!

🔀 Ulike framgangsmåtar

Ser på tre ulike framgangsmåtar her
1️⃣ “rett fram” med løkker (treg måte 🐢)
2️⃣ fancy versjon av 1️⃣ (men enno tregare 🐌)
3️⃣ ingen løkker, kun arrays 👑 (rask måte )

💡 Om du er fan av eleganse og fart kan du hoppa rett til 3️⃣

1️⃣ Løkker

Tanken her er å trekka ein elev N gongar. Trekk eit tal mellom 0 og 323+301, og seier at dei 323 første (fom. 0 tom. 322) er jenter, og dei siste (resten) er gutar. Simulerer høgda til kvar elev etter det. Tel til slutt opp kor mange som er over 175 cm.

import numpy as np
rng = np.random.default_rng()

# tal simuleringar
N = 10000000

# N elevar (tal mellom 0 og 323+301)
elevar = rng.integers(0, (323+301), size=N)

# tom liste til høgdene
høgdar = []

# Finn høgda til kvar elev
for elev in elevar:
    if elev<323: # 0 til 322 er jenter
        høgdar.append(rng.normal(168, 6))
    else: # 323 til 323+301 er gutar
        høgdar.append(rng.normal(180, 8))

# tel opp elevar høgare enn 175 cm
gunstige = sum(np.array(høgdar)>175)
sannsyn = gunstige / N

print(f"Sannsynet for at ein tilfeldig elev er høgare enn 175 cm er {sannsyn:.4f}")
Sannsynet for at ein tilfeldig elev er høgare enn 175 cm er 0.4172

Her brukte maskina mi ca. 17 sek. på 10 000 000 simuleringar.

2️⃣ funksjonar…

Her gjer me 1️⃣ litt meir fancy. Mykje lik tankegang.

import numpy as np
rng = np.random.default_rng()

# tal simuleringar
N = 10000000

# finn sannsyn jente og sannsyn gutt
p = np.array([323, 301]) / (323+301)

# lagar funksjon som trekk ein elev
def trekk_elev(p):
    høgde = 0
    # trekk kjønn:
    kjønn = rng.choice(['j', 'g'], p=p)
    
    # trekk høgde (ut frå trekt kjønn)
    if kjønn == 'j':
        høgde = rng.normal(168, 6, 1)
    else: 
        høgde = rng.normal(180, 8, 1)
    
    return høgde[0]

# tel opp talet elevar som er over 175 cm
gunstig = 0

for i in range(N):
    h = trekk_elev(p)
    if h>175:
        gunstig += 1

# finn og skriv ut relativ frekvens
sannsyn = gunstig/N
print(f"Sannsynet for at ein tilfeldig elev er høgare enn 175 cm er {sannsyn:.4f}")
Sannsynet for at ein tilfeldig elev er høgare enn 175 cm er 0.4169

Her brukte maskina mi ca. 5 min. (!!!) på 10 000 000 simuleringar.

3️⃣ Alt i arrays 🚀

For å gjera programmet effektivt, raskt og lett leseleg droppar eg løkker og funksjonar.

import numpy as np
rng = np.random.default_rng()

# antall jenter, gutar og elevar på skulen
j = 323
g = 301
n = j + g

# tal simuleringar
N = 10000000

# finn antall gutar (0) og jenter (1)
kjønn = rng.choice([0,1], size=N, p=[g/n, j/n])
jenter = sum(kjønn)
gutar = N - jenter

# finn høgder på jenter og gutar for seg
h_jenter = rng.normal(168, 6, size=jenter)
h_gutar = rng.normal(180, 8, size=gutar)

# høgder på alle dei trekte elevane
h_trekte = np.append(h_jenter, h_gutar)

# reknar ut sannsynet
gunstige = sum(h_trekte > 175)
sannsyn = gunstige / N

print(f"Sannsynet for at ein tilfeldig elev er høgare enn 175 cm er {sannsyn:.4f}")
Sannsynet for at ein tilfeldig elev er høgare enn 175 cm er 0.4168

3,4 sek. på 10 000 000 simuleringar! 😎

Oppsummert

Dette var eit lite innblikk i ulike måtar ei oppgåve som dette kan løysast på ved hjelp av simulering. Ville nok valgt den elegante og raske versjonen (3️⃣) sjølv.

Gje gjerne eit pip om du lurer på noko ⬇️ Plutseleg attende med nye innlegg ✌️

Gjenbruk