Nyttige simuleringskommandoar

Her er ei oversikt over nyttige tips og triks til simulering i Python. Det kan jo vera kjekt til eksamen 🥳
programmering
s-matte
simulering
eksamen
Forfattar

Torodd F. Ottestad

Publisert

May 11, 2023

Komme i gang

Standard importering og oppsett av tilfeldighetsgenerator frå NumPy.

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

Uniforme modellar

Ofte enkelt å bruke heiltal når ein skal simulere noko med uniform sannsynsmodell - ein terning 🎲, myntkast 🪙, gut/jente 👫 osv.

Døme - myntkast

Viss ein skal simulera myntkast kan ein la 0 vera mynt og 1 vera kron.

# antall kast
N = 10

# kasta simulert
mynt_kast = rng.integers(0, 2, size=N)

print(mynt_kast)
[1 0 1 1 1 0 0 0 1 0]

Dermed kan ein enkelt telja opp kor mange kron det var:

sum(mynt_kast)
5

Binomiske fordelingar

Viss me ser på noko som er binomisk fordelt er rng.binomial(n, p) fin å nytta. n er antall suksess og p er sannsynet for suksess i kvart delforsøk. Her og kan ein bruka size= for å gjenta forsøket fleire gongar.

Døme

Plantar 100 frø. Sannsynet for at eitt frø spirer er 0.7 🌱

Dette kan me simulera:

# simulererer forsøket N gongar
N = 10

spirer = rng.binomial(n=100, p=0.7, size=N)
print(spirer)
[67 73 73 65 74 71 69 74 65 76]

Tala her viser kor mange av dei 100 frøa som spirte i kvar av dei 10 gjennomførte forsøka.

Me kan telja opp kor mange av forsøka som tilfredsstiller eit vilkår. T.d. kor mange gongar spira 70 eller fleire av frøa?

spirer >= 70
array([False,  True,  True, False,  True,  True, False,  True, False,
        True])

Ser at me her får sanningsvariablar. Python reknar false som 0 og true som 1. Dermed blir det lett å telja opp:

sum(spirer >= 70)
6

Då kan me finna sannsynet på denne oppgåva ved simulering.

Du plantar 100 frø, sannsynet for at eitt frø spirer er 0.7. Kva er sannsynet for at 70 eller fleire av frøa spirer?

# antall forsøk
N = 1000000

# simulering
spirer = rng.binomial(n=100, p=0.7, size=N)

# tel opp gunstige utfall
gunstige = sum(spirer >= 70)

# finn relativ frekvens
sannsyn = gunstige / N 

# skriv ut sannsynet med 4 desimalar
print(f"P(X ≥ 70) = {sannsyn:.4f}")
P(X ≥ 70) = 0.5490

Hypergeometriske fordelingar

For hypergeometriske fordelingar kan ein nytta rng.hypergeometric(ngood, nbad, nsample). I hypergeometriske fordelingar er populasjonen delt i to. ngood og nbad er storleiken på kvar av dei. nsample er storleiken på utvalet du trekk frå populasjonen.

Det ligg 12 raude og 7 blå kuler i ei korg. Du trekk ut 5 kuler. Kva er sannsynet for at minst to av dei er raude?

N = 10

# definerer kuleantall og utvalstorleik
raude = 12
blå = 7
utval = 5

# simulerer 10 trekk
rng.hypergeometric(ngood=raude, nbad=blå, nsample=utval, size=N)
array([2, 4, 3, 3, 3, 3, 2, 3, 3, 3])

Tala me får ut her er antall raude (ngood) i kvart forsøk. Resten av utvalet blir då blå.

Bruker dette til å løysa oppgåva.

N = 1000000

# definerer kuleantall og utvalstorleik
raude = 12
blå = 7
utval = 5

# simulerer 
trekte_kuler = rng.hypergeometric(
    ngood=raude, 
    nbad=blå, 
    nsample=utval, 
    size=N
)

# tel opp gunstige
gunstige = sum(trekte_kuler >= 2)

sannsyn = gunstige / N
print(f"P(minst to raude) = {sannsyn:.4f}")
P(minst to raude) = 0.9619

Normalfordeling

Her bruker me rng.normal(loc, scale) der loc er gjennomsnittet/forventningsverdien (\(\mu\)) og scale er standardavviket (\(\sigma\)).

Døme

På ein skule er gjennomsnittshøgda på elevane 172 cm og standardavviket 9 cm. Kva er sannsynet for at ein tilfeldig elev er høgare enn 180 cm?

N = 1000000

# trekk tilfeldige elevar
elevar = rng.normal(loc=172, scale=9, size=N)

# tel opp og finn sannsynet
gunstige = sum(elevar > 180)
sannsyn = gunstige / N

print(f"Sannsynet er {sannsyn:.4f}")
Sannsynet er 0.1876
Samansett simulering

I dette innlegget har eg vist korleis simuleringsoppgåva frå eksempelsettet til S2 kan løysast (på tre ulike måtar).

I tillegg denne er rng.standard_normal() eit alternativ om ein jobbar med noko som er standard normalfordelt.

Også nyttig - rng.choice()

Trekke andre ting enn tal med rng.choice

I ei skål ligg det 7 banan-twist og 3 daim-twist. Kva er sannsynet for at me får to banan når me trekk ut to bitar frå skåla.

Startar med å “lage” twistskåla.

twistskål = ["Banan"]*7 + ["Daim"]*3
print(twistskål)
['Banan', 'Banan', 'Banan', 'Banan', 'Banan', 'Banan', 'Banan', 'Daim', 'Daim', 'Daim']

med tilbakelegging

Ser først på forsøket med tilbakelegging (dette er default i choice).

N = 1000000

# tellevariabel BB <- banan+banan
BB = 0

for i in range(N):
    trekt_twist = rng.choice(a=twistskål, size = 2)
    # legg til 1 om bit1 OG bit2 er banan. Legg til 0 om ikkje... 
    BB += ((trekt_twist[0] == "Banan") and (trekt_twist[1] == "Banan"))

sannsyn = BB / N
print(f"P(BB) = {sannsyn:.4f}")
P(BB) = 0.4897

utan tilbakelegging

Dette er nesten heilt likt, men me legg til argumentet replace=False.

N = 1000000

# tellevariabel BB <- banan+banan
BB = 0

for i in range(N):
    trekt_twist = rng.choice(a=twistskål, size = 2, replace=False)
    BB += ((trekt_twist[0] == "Banan") and (trekt_twist[1] == "Banan"))

sannsyn = BB / N
print(f"P(BB) = {sannsyn:.4f}")
P(BB) = 0.4661

ikkje-uniformt sannsyn

Sannsynet over var ikkje-uniformt, men såpass enkelt at me laga ei liste med heile utfallsrommet. Det vert fort upraktisk om me har mange ulike utfall med store variasjonar i antall. Me kan heller legga inn sannsynet for kvart av utfalla direkte i rng.choice()

twistar = ["Banan", "Daim"]
sannsyn = [7/10, 3/10]

to_twist = rng.choice(a=twistar, size=2, p=sannsyn)
print(to_twist)
['Banan' 'Daim']

Dette er fint t.d. ved simulering av lykkehjul der ulike fargar har ulik storleik, eller for å simulera blodtype hos menneske.

Oppsummering

Det var ein kort gjennomgang av dei viktigaste kommandoane me treng for simulering i S1 og S2. Det er ei rekka andre valg i random number generator-en. Sjekk gjerne ut dokumentasjonen.

Denne sida kan du lagra og ha med på eksamen om du vil 😎

Lykke til! 🧑‍🎓


Miniatyrbilete laga av katemangostar på Freepik

Gjenbruk