Jeg trenger å generere tilfeldige tall etter Normalfordeling innenfor intervallet $ (a, b) $. (Jeg jobber i R.)

Jeg vet at funksjonen rnorm(n,mean,sd) vil generere tilfeldige tall etter normalfordeling, men hvordan setter jeg intervallgrensene innenfor det? Er det noen spesielle R-funksjoner tilgjengelig for det?

Kommentarer

  • Hvorfor vil du gjøre dette? Hvis den ‘ er avgrenset, kan den ‘ ikke være normal. Hva prøver du å oppnå?
  • x <- rnorm(n, mean, sd); x <- x[x > lower.limit & x < upper.limit]
  • @Hugh that ‘ is great … så lenge du ikke ‘ ikke bryr deg om hvor mange tilfeldige verdier du får.

Svar

Det høres ut som om du vil simulere fra en avkortet distribusjon , og i ditt spesifikke eksempel , en avkortet normal .

Det finnes en rekke metoder for å gjøre det, noen enkle, noen relativt effektiv.

Jeg vil illustrere noen tilnærminger på ditt normale eksempel.

  1. Her er en veldig enkel metode for å generere en om gangen (i en slags pseudokode ):

    $ \ tt {repeat} $ generer $ x_i $ fra N (gjennomsnitt, sd) $ \ tt {til} $ lavere $ \ leq x_i \ leq $ øvre

    skriv inn bildebeskrivelse her

    Hvis det meste av fordelingen er innenfor grensene, er dette ganske rimelig, men det kan bli ganske sakte hvis genererer du nesten alltid utenfor grensene.

    I R kan du unngå en av gangen løkke ved å beregne området innenfor grensene og generere nok verdier til at du kan være nesten sikker på at etter å ha kastet ut verdiene utenfor grensene hadde du fremdeles så mange verdier som trengs.

  2. Du kan bruke accept-refject med en passende majoriseringsfunksjon over intervallet (i noen tilfeller uniform vil være god nok). Hvis grensene var rimelig smale i forhold til s.d. men du var ikke langt inn i halen, for eksempel ville en uniform majorizing fungere greit med det normale.

    skriv inn bildebeskrivelse her

  3. Hvis du har en rimelig effektiv cdf og invers cdf (for eksempel pnorm og qnorm for normalfordeling i R) kan du bruke invers-cdf-metoden beskrevet i første avsnitt av simuleringsdelen av Wikipedia-siden på den avkortede normal . [I kraft dette er det samme som å ta en avkortet uniform (avkortet på de nødvendige kvantilene, som faktisk ikke krever noen avvisning i det hele tatt, siden det bare er en uniform) og bruke den omvendte normale cdf på det. Merk at dette kan mislykkes hvis du «kommer langt inn i halen]

    skriv inn bildebeskrivelse her

  4. Det er andre tilnærminger; den samme Wikipedia-siden nevner å tilpasse ziggurat -metoden, som skal fungere for en rekke distribusjoner.

samme Wikipedia-lenke nevner to spesifikke pakker (begge på CRAN) med funksjoner for å generere avkortede normaler:

MSM -pakken i R har en funksjon, rtnorm, som beregner tegninger fra en avkortet normal. truncnorm -pakken i R har også funksjoner for å tegne fra en avkortet normal.


Når man ser seg rundt, blir mye av dette dekket av svar på andre spørsmål (men ikke akkurat duplikater siden dette spørsmålet er mer generelt enn bare den avkortede normalen) … se ytterligere diskusjon i

a. Dette svaret

b. Xi «et» svar her , som har en lenke til arXiv-papiret (sammen med noen andre verdifulle svar).

Svar

Den raske og skitne tilnærmingen er å bruke 68-95-99.7 regelen .

I en normalfordeling faller 99,7% av verdiene innenfor 3 standardavvik fra gjennomsnittet. Så hvis du setter middelverdien til midten av ønsket minimumsverdi og maksimumsverdi, og setter standardavviket til 1/3 av gjennomsnittet ditt, får du (for det meste) verdier som faller innenfor ønsket intervall. Så kan du bare rydde opp resten.

minVal <- 0 maxVal <- 100 mn <- (maxVal - minVal)/2 # Generate numbers (mostly) from min to max x <- rnorm(count, mean = mn, sd = mn/3) # Do something about the out-of-bounds generated values x <- pmax(minVal, x) x <- pmin(maxVal, x) 

Jeg møtte nylig det samme problemet og prøvde å generere tilfeldige studentkarakterer for testdata. I koden ovenfor har jeg brukt pmax og pmin for å erstatte verdier utenfor grensene med min eller maks. verdi.Dette fungerer for mitt formål fordi jeg genererer ganske små datamengder, men for større mengder vil det gi deg merkbare støt på min- og maksverdiene. Så avhengig av dine formål kan det være bedre å forkaste disse verdiene, erstatt dem med NA s, eller «rull» dem på nytt til de «kommer inn igjen.

Kommentarer

  • Hvorfor gidder å gjøre dette? Det er så enkelt å generere normale tilfeldige tall og slippe de som trenger avkorting at det ikke er ‘ som er nødvendig for å være komplisert, med mindre ønsket avkutting er nær 100% av området av tettheten.
  • Kanskje jeg ‘ mistolker det originale spørsmålet. Jeg kom over dette spørsmålet mens jeg prøvde å finne ut hvordan jeg kunne oppnå en ikke-direkte statistikk-relatert programmeringsoppgave i R, og jeg ‘ har bare nå lagt merke til at denne siden er en statistikk stackexchange , ikke en programmeringsstakbytte. 🙂 I mitt tilfelle ønsket jeg å generere en bestemt mengde tilfeldige heltall, med verdier fra 0 til 100, og jeg ønsket at de genererte verdiene skulle falle på en fin bjellekurve over det området. Siden jeg skrev dette, har jeg ‘ innsett at sample(x=min:max, prob=dnorm(...)) er kanskje en enklere måte å gjøre det på.
  • @Glen_b Aaron Wells nevner sample(x=min:max, prob=dnorm(...)) som virker litt kortere enn svaret ditt.
  • Men vær oppmerksom på at sample() trikset bare er nyttig hvis du ‘ prøver å velge tilfeldige heltall eller et annet sett med diskrete, forhåndsdefinerte verdier.

Svar

Ingen av svarene her gir en effektiv metode for å generere avkortede normale variabler som ikke innebærer avvisning av vilkårlig store antall genererte verdier. Hvis du vil generere verdier fra en avkortet normalfordeling, med spesifiserte nedre og øvre grenser $ a < b $ , dette kan gjøres — uten avvisning — ved å generere ensartede kvantiler over kvantilområdet tillatt av avkuttingen, og bruke invers transformasjonssampling for å få tilsvarende normale verdier .

La $ \ Phi $ betegne CDF for standard normalfordeling. Vi vil generere $ X_1, …, X_N $ fra en avkortet normalfordeling (med gjennomsnittlig parameter $ \ mu $ og variansparameter $ \ sigma ^ 2 $ ) $ ^ \ dolk $ med lavere og øvre avkuttingsgrenser $ a < b $ . Dette kan gjøres som følger:

$$ X_i = \ mu + \ sigma \ cdot \ Phi ^ {- 1} (U_i) \ quad \ quad \ quad U_1, …, U_N \ sim \ text {IID U} \ Big [\ Phi \ Big (\ frac {a- \ mu} {\ sigma} \ Big), \ Phi \ Big (\ frac {b- \ mu} {\ sigma} \ Big) \ Big]. $$

Det er ingen innebygd funksjon for genererte verdier fra den avkortede distribusjonen, men det er trivielt å programmere denne metoden ved hjelp av vanlige funksjoner for å generere tilfeldige variabler. Her er en enkel R -funksjon rtruncnorm som implementerer denne metoden i noen få kodelinjer.

rtruncnorm <- function(N, mean = 0, sd = 1, a = -Inf, b = Inf) { if (a > b) stop("Error: Truncation range is empty"); U <- runif(N, pnorm(a, mean, sd), pnorm(b, mean, sd)); qnorm(U, mean, sd); } 

Dette er en vektorisert funksjon som vil generere N IID tilfeldige variabler fra den avkortede normalfordelingen. Det ville være enkelt å programmere funksjoner for andre avkortede distribusjoner via samme metode. Det ville heller ikke være for vanskelig å programmere tilknyttede tetthets- og kvantilfunksjoner for den avkortede fordelingen.


$ ^ \ dolk $ Merk at avkuttingen endrer gjennomsnittet og variansen til fordelingen, så $ \ mu $ og $ \ sigma ^ 2 $ er ikke gjennomsnittet og variansen til den avkortede fordelingen.

Svar

Tre måter har fungert for meg:

  1. ved å bruke sample () med rnorm ():

    sample(x=min:max, replace= TRUE, rnorm(n, mean))

  2. ved hjelp av msm-pakken og rtnorm-funksjonen:

    rtnorm(n, mean, lower=min, upper=max)

  3. ved hjelp av rnorm () og spesifiserer de nedre og øvre grensene, slik Hugh har skrevet ovenfor:

    sample <- rnorm(n, mean=mean); sample <- sample[x > min & x < max]

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *