7.1 Inversjonsmetoden og numpy-verktøykassen
Fra F⁻¹ på papir til kjørbar numpy-funksjon: simuler fra en vilkårlig fordeling med inversjonsmetoden.
- Simulering/Python (sjanger I) dukker opp i 6 av 10 sett (60 %), jevnt fordelt siden 2015. «Sjanger I» er vår kode for simulering, bootstrap og Python — oppgaver der du skal trekke tilfeldige tall og regne på dem.
- Inversjonsmetoden spesielt: Laplace-fordeling (V2016), Rayleigh (V2019). Fra og med V2020 forventer fasiten full, kjørbar Python-kode — ikke bare en beskrivelse.
- Sensorkrav 10: koden skal være korrekt og kjørbar. Delvis eller ikke-kjørende kode gir bare delvis uttelling. All kode i denne boka er faktisk kjørt før den ble skrevet — kjør den selv også.
Prioritet: kunne (nivå 2). Dette er ikke det tyngste temaet, men det er lavthengende poeng for den som har øvd på idiomene. Målet i dette kapitlet: gå fra på papir til en numpy-funksjon som faktisk kjører.
ddof=1 i koden).Sist du var her — de tre tingene du må ha friskt:
1. Fordelingsfunksjonen — voksende, fra 0 til 1.
2. Den inverse : løser du for , får du . For en voksende, kontinuerlig finnes den entydig for .
3. Eksponensialfordelingen (forventnings-parametrisering, forventning ): tetthet , fordelingsfunksjon for . (Rate-parametriseringen , bruker vi der oppgaven gjør det — les alltid oppgavens egen definisjon.)
Tenk deg at du vil vite hvor ofte en komponent med tilfeldig levetid varer i mer enn 8 år, eller hva forventet verdi av en komplisert funksjon av flere variable er — men integralet er stygt eller finnes ikke i lukket form. I stedet for å regne kan du la datamaskinen «kaste terning» én million ganger og telle. Det er hele idéen bak simulering: en sannsynlighet er en andel, og en forventning er et gjennomsnitt, så trekker vi mange nok realisasjoner, leser vi svaret rett ut av tallene.
Men datamaskinen kan i utgangspunktet bare trekke uniforme tall mellom 0 og 1 (np.random.uniform). Spørsmålet blir da: hvordan lager vi tall fra vår fordeling — eksponensial, Pareto, Rayleigh — ut fra uniforme tall? Svaret er inversjonsmetoden, og den er kapitlets første halvdel. Andre halvdel er numpy-verktøykassen: de få funksjonene og idiomene sensor forventer å se, og hvordan du leser en simuleringssnutt.
Kapitlet er bygget som fire korte læringsløkker — teori → gjennomregnet eksempel → øvingsoppgave — så du kan ta én om gangen. Med fire løkker à ~13 min passer det med en kort pause etter løkke 2.
Løkke 1 — Inversjonsmetoden (~15 min)
nettopp fordelingsfunksjonen . Med andre ord: trekker du et uniformt tall og setter det inn i , får du en realisasjon fra fordelingen med fordelingsfunksjon .
Intuisjon steg 1: Vi bruker at er voksende, så er det samme som (vi «kjører på begge sider»).
Intuisjon steg 2: Siden er uniform på , er for enhver mellom 0 og 1 — og ligger nettopp mellom 0 og 1. Derfor blir .
Intuisjon steg 3: Resultatet er per definisjon fordelingsfunksjonen til . Ferdig — har fordelingen vi ville ha.
Arbeidsflyten blir dermed alltid den samme:
1. Skaff fordelingsfunksjonen (utledet i kap. 2.3).
2. Løs likningen for — det gir formelen .
3. Implementer: trekk uniforme -er og sett dem inn i formelen.
Levetiden (i år) til en sensor er eksponensialfordelt med forventning , altså for . Utled inversjonsformelen , og skriv en Python-funksjon som trekker realisasjoner. Kontroller at gjennomsnitt og empirisk varians stemmer med teorien (, ).
Så .
Steg 3 — implementer og kontroller:
import numpy as np
def simuler_eksp(n, mu):
u = np.random.uniform(size=n)
return -mu * np.log(1 - u)
np.random.seed(1)
x = simuler_eksp(10**6, 5.0)
print(np.mean(x), np.var(x, ddof=1))
# 4.9971... 24.9402...Gjennomsnittet ligger på og den empiriske variansen på — akkurat de teoretiske verdiene og , med litt Monte Carlo-støy. Koden kjører og bekrefter at inversjonsformelen er riktig.
Merk ddof=1: np.var(x, ddof=1) deler på og gir den forventningsrette empiriske variansen (kobling kap. 5.1). Standard np.var deler på ; med er forskjellen mikroskopisk, men sensor vil se ddof=1 der du estimerer en varians.
(Innsteg.) En variabel har fordelingsfunksjon for (eksponensial, forventning ). Løs likningen for , og skriv ned inversjonsformelen .
En oppgave bruker rate-parametriseringen av eksponensialfordelingen: , altså for , med rate .
a) Utled inversjonsformelen i denne parametriseringen.
b) Skriv en Python-funksjon simuler(n, lam) som trekker realisasjoner, og forklar hvorfor svaret er konsistent med forventnings-formen når .
Løkke 2 — numpy-verktøykassen (~15 min)
— naturlig pausepunkt etter denne løkka —
Inversjonsmetoden lager tallene; numpy og scipy.stats regner på dem. Her er hele verktøykassen sensor forventer — det er ikke mange funksjoner:
- np.random.uniform(size=n) — trekker uniforme tall på . Dette er råstoffet til inversjonsmetoden.
- stats.norm.rvs(mu, sigma, size=n) — trekker normalfordelte tall. Advarsel: annet argument er STANDARDAVVIKET , ikke variansen. Skriver du variansen der, får du feil spredning (en klassisk sensorfelle). For med skriver du stats.norm.rvs(mu, 3, size=n) — altså 3, ikke 9.
- np.mean(x) — gjennomsnittet, estimatet av .
- np.var(x, ddof=1) og np.std(x, ddof=1) — empirisk varians og standardavvik. ddof=1 betyr «del på », som gir den forventningsrette variansen (kobling kap. 5.1). Uten ddof=1 deler numpy på og gir en litt for liten varians.
- Vektorisering. Skriv -mu * np.log(1 - u) på hele vektoren u på én gang — ikke en for-løkke over enkeltelementer. Vektorisert kode er kortere, raskere og det sensor forventer.
Funksjonsmønsteret som går igjen:
def simuler(n):
u = np.random.uniform(size=n)
return ... # inversjonsformelen anvendt vektorisert på uKonsentrasjonen (mg/l) av et stoff er med forventning og varians . Trekk realisasjoner med stats.norm.rvs, og kontroller gjennomsnitt og empirisk standardavvik. Hva er den vanligste feilen her?
Variansen er , så standardavviket er . Det er — ikke — som skal inn som annet argument:
import numpy as np
from scipy import stats
np.random.seed(3)
y = stats.norm.rvs(10, 2, size=10**6) # 2 = standardavviket (ikke variansen 4!)
print(np.mean(y), np.std(y, ddof=1))
# 10.0039... 1.9966...Gjennomsnittet ligger på og empirisk standardavvik på .
Den vanligste feilen er å skrive stats.norm.rvs(10, 4, ...) — da sender du variansen der funksjonen vil ha standardavviket, og får spredning i stedet for . Empirisk standardavvik ville da blitt , og alle etterfølgende sannsynligheter feil. Les alltid dokumentasjonen: scale = standardavvik.
En medstudent vil trekke fra med og varians , og skriver stats.norm.rvs(100, 25, size=n). Forklar hva som er galt, og skriv den korrekte linjen.
Skriv om denne løkke-baserte koden til vektorisert numpy, og forklar én fordel utover hastighet:
x = []
for i in range(n):
u = np.random.uniform()
x.append(-mu * np.log(1 - u))Løkke 3 — Haler og flere fordelinger (~15 min)
Inversjonsmetoden virker for enhver fordeling der du klarer å løse . De «eksotiske» fordelingene fra kap. 2.3 gir alle pene inversjonsformler:
- Pareto (hale, minsteverdi , formparameter ): for , som gir .
- Weibull (skala , form ): , som gir .
- Rayleigh (skala ): , som gir .
Hver av dem er samme tre-stegs oppskrift: skaff , løs for , implementer vektorisert.
Bølgehøyden (i meter) har tetthet for . Finn og , skriv en Python-funksjon som trekker realisasjoner, og bruk den til å estimere . Sammenlign med den eksakte verdien.
Invers. — altså med .
Eksakt : .
Kode:
import numpy as np
def simuler_pareto(n, k, theta):
u = np.random.uniform(size=n)
return k * (1 - u)**(-1/theta)
np.random.seed(2)
x = simuler_pareto(10**6, 1.0, 4.0)
print(np.mean(x > 2))
# 0.06287...Her er x > 2 et array med True/False; np.mean av det er andelen True — altså estimatet av . Vi får , mot den eksakte . Stemmer.
Vindstyrken er Rayleigh-fordelt med skala : for .
a) Utled inversjonsformelen .
b) Skriv en Python-funksjon simuler_rayleigh(n, sigma) og bruk den (med ) til å estimere forventningen. Den teoretiske er — stemmer estimatet?
Levetiden (i tusen timer) til en fiber er Weibull-fordelt: for , med form og skala .
a) Utled og skriv en simuleringsfunksjon.
b) Bruk simulering til å estimere medianen, og sammenlign med den eksakte medianen .
c) Forklar kort hvorfor inversjonsmetoden fungerer like godt her som for eksponensial, selv om Weibull ikke har «minneløshet».
Løkke 4 — Kodelesing som ferdighet (~15 min)
Eksamen ber deg ikke bare skrive kode — den ber deg lese en snutt og svare på to spørsmål: (1) hvilken fordeling trekkes det fra, og (2) hva estimeres? Framgangsmåten:
1. Finn inversjonsformelen i koden og kjenn den igjen. -mu*np.log(1-u) er eksponensial; k*(1-u)**(-1/theta) er Pareto; sigma*np.sqrt(-2*np.log(1-u)) er Rayleigh.
2. Les den siste linjen — estimandet. np.mean(x) estimerer ; np.var(x, ddof=1) estimerer ; np.mean(x > a) estimerer (gjennomsnitt av en indikator er en sannsynlighet); np.mean(g(x)) estimerer .
Nøkkelen til punkt 2: en sannsynlighet er en forventet indikator. x > a er en vektor av True/False (1/0), og gjennomsnittet av den er andelen som oppfyller betingelsen — altså et estimat av .
Hva trekker denne koden fra, og hva estimerer siste linje?
import numpy as np
np.random.seed(4)
u = np.random.uniform(size=10**6)
x = -5 * np.log(1 - u)
print(np.mean(x > 2))-5*np.log(1-u) er med — altså eksponensialfordeling med forventning .Estimand: x > 2 er en indikatorvektor, og np.mean av den er andelen realisasjoner større enn 2 — et estimat av .
Kontroll: For eksponensial med forventning er .
# kjører koden over gir:
# 0.67048...
# mot eksakt e^{-0.4} = 0.67032...Svaret: koden estimerer for en eksponensialfordeling med forventning 5.
(Kodelesing.) Hva trekker koden fra, og hva estimerer siste linje? Gi også den eksakte verdien.
import numpy as np
np.random.seed(0)
u = np.random.uniform(size=10**6)
x = 1 * (1 - u)**(-1/4)
print(np.mean(x))(Kodelesing + feilsøk.) En student vil estimere for en eksponensialfordeling med forventning og skriver:
import numpy as np
u = np.random.uniform(size=10**6)
x = -5 * np.log(u)
print(np.mean(x > 8))a) Er koden riktig? Forklar hva -5*np.log(u) trekker fra.
b) Hva estimerer siste linje, og hva er den eksakte verdien den bør ligge nær?
- Løse i stedet for . Inversjonsmetoden bruker fordelingsfunksjonen , ikke tettheten . Å invertere gir tull. Skaff alltid først (integrer ).
- Sende variansen der scale = standardavvik kreves. stats.norm.rvs(mu, sigma, size=n) vil ha , ikke . Har du variansen, ta kvadratroten først.
- np.var/np.std uten ddof=1. Da deles det på , og du estimerer en litt for liten varians. Bruk ddof=1 når du estimerer varians/standardfeil (kobling kap. 5.1).
- for-løkke der vektorisering er naturlig. Behandle hele u-vektoren på én gang: -mu*np.log(1-u). Løkke over enkeltelementer er tregt og unødvendig.
- Kode som ikke kjører. Delvis eller ikke-kjørbar kode gir bare delvis uttelling (sensorkrav 10). Test snutten før du leverer — importér numpy, definer alt, kjør.
Begrepsbank
Flashcard-/repetisjonsstoff — hopp trygt over ved førstegangslesing; tidsanslaget gjelder kjernestoffet. Kortene under samler metodene og idiomene til rask repetisjon.
Å simulere fra en fordeling ved å trekke uniforme tall og sette dem inn i den inverse fordelingsfunksjonen. I symboler: er uniform, har fordelingsfunksjon . Arbeidsflyt: skaff , løs for , implementer.
Datamaskinens grunnleggende tilfeldighet: tall jevnt fordelt mellom 0 og 1. I kode np.random.uniform(size=n). All annen simulering (inversjonsmetoden) bygger på å transformere disse tallene. Egenskap: for .
Sannsynligheten for å ligge til og med et punkt: . Voksende, går fra 0 til 1. Inversjonsmetodens første ingrediens — den skaffes ved å integrere tettheten .
Løsningen av med hensyn på ; kalles også kvantilfunksjonen. For en voksende, kontinuerlig finnes den entydig for . Det er denne du setter uniforme tall inn i.
For er inversjonsformelen . Grunnformelen i simulering — kjenn den igjen både når du skriver og leser kode.
For er inversjonsformelen . Samme tall som forventnings-formen når ; les alltid oppgavens egen parametrisering.
For , , er inversjonsformelen . Hale-fordeling med minsteverdi og form .
For er inversjonsformelen . Skala , form ; eksponensial er spesialtilfellet .
For er inversjonsformelen . Ta den positive roten siden .
Trekker uniforme tall på som et array. Råstoffet til inversjonsmetoden. Argumentet size bestemmer antallet — bruk det i stedet for en løkke.
Trekker normalfordelte tall. Annet argument er standardavviket , ikke variansen . For med : skriv stats.norm.rvs(mu, 3, size=n).
Å regne på hele arrayet på én gang — -mu*np.log(1-u) — i stedet for en for-løkke over enkeltelementer. Kortere, raskere, og det sensor forventer. np.log, *, > og lignende virker elementvis.
Gjennomsnittet av realisasjonene er estimatet av forventningen. Store talls lov gjør at når er stor.
Den empiriske variansen med divisor — den forventningsrette varianten (kobling kap. 5.1). Estimerer .
Det empiriske standardavviket, , med divisor . Brukes som estimat av standardavvik og som byggekloss i standardfeil.
«Delta degrees of freedom» = 1 gjør at det deles på i stedet for . Det gir en forventningsrett estimator av variansen; med divisor blir estimatet systematisk litt for lite (kobling kap. 5.1).
En sannsynlighet er en andel: np.mean(x > a) estimerer fordi x > a er en vektor av 1/0 (True/False) og gjennomsnittet er andelen som er sanne. Generelt estimerer np.mean(g(x)) forventningen .
Egen ferdighet: gitt en snutt, identifiser (1) fordelingen fra inversjonsformelen i koden, og (2) estimandet fra siste linje (np.mean → , np.mean(x>a) → , np.var(...,ddof=1) → varians).
Standardoppsettet: def simuler(n): u = np.random.uniform(size=n); return <inversjonsformel>. Gjør simuleringen gjenbrukbar og lett å teste — kall simuler(10**6) og send resultatet til np.mean osv.
Er uniform, er også uniform. Derfor gir både og korrekte eksponensiale tall. Snarveien er vanlig, men skriv når du følger inversjonsformelen bokstavelig.
Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.
Skolesaga er en uavhengig læringsressurs og er ikke tilknyttet eller godkjent av Universitetet i Oslo. Dette er ikke offisielt studiemateriell. Les mer.