Ho bisogno di generare numeri casuali seguendo la distribuzione Normale allinterno dellintervallo $ (a, b) $. (Sto lavorando in R.)

So che la funzione rnorm(n,mean,sd) genererà numeri casuali seguendo la distribuzione normale, ma come impostare i limiti dellintervallo entro questo? Sono disponibili funzioni R particolari per questo?

Commenti

  • Perché vuoi farlo? Se ‘ è limitato, ‘ non può essere veramente normale. Cosa stai cercando di ottenere?
  • x <- rnorm(n, mean, sd); x <- x[x > lower.limit & x < upper.limit]
  • @Hugh che ‘ è fantastico … a patto che ‘ non importi quanti valori casuali ottieni.

Rispondi

Sembra che tu voglia simulare da una distribuzione troncata e nel tuo esempio specifico , un normale troncato .

Esistono vari metodi per farlo, alcuni semplici, altri relativamente efficiente.

Illustrerò alcuni approcci al tuo esempio normale.

  1. Ecco un metodo molto semplice per generarne uno alla volta (in una sorta di pseudocodice ):

    $ \ tt {repeat} $ genera $ x_i $ da N (mean, sd) $ \ tt {until} $ lower $ \ leq x_i \ leq $ upper

    inserisci qui la descrizione dellimmagine

    Se la maggior parte della distribuzione è entro i limiti, è abbastanza ragionevole ma può diventare piuttosto lenta se generi quasi sempre al di fuori dei limiti.

    In R potresti evitare il ciclo uno alla volta calcolando larea entro i limiti e generare valori sufficienti per essere quasi certo che dopo aver buttato fuori i valori al di fuori dei limiti avevi ancora tutti i valori necessari.

  2. Potresti usare accetta-rifiuta con qualche funzione di majorizing adatta nellintervallo (in alcuni casi sarà uniforme essere abbastanza buono). Se i limiti fossero ragionevolmente stretti rispetto alla s.d. ma non eri “lontano nella coda, una majorizing uniforme funzionerebbe bene con il normale, ad esempio.

    inserisci la descrizione dellimmagine qui

  3. Se hai un cdf ragionevolmente efficiente e un cdf inverso (come pnorm e qnorm per il distribuzione normale in R) puoi utilizzare il metodo inverse-cdf descritto nel primo paragrafo della sezione di simulazione della pagina di Wikipedia sulla normale troncata . [In effetti questo è lo stesso che prendere una uniforme troncata (troncata ai quantili richiesti, che in realtà non richiede alcun rifiuto, dato che è solo unaltra uniforme) e applicare la normale inversa cdf a quella. Tieni presente che questa operazione può non riuscire se “sei molto in coda]

    inserisci qui la descrizione dellimmagine

  4. Esistono altri approcci; la stessa pagina di Wikipedia menziona ladattamento del metodo ziggurat , che dovrebbe funzionare per una varietà di distribuzioni.

Lo stesso link di Wikipedia menziona due pacchetti specifici (entrambi su CRAN) con funzioni per la generazione di normali troncate:

Il pacchetto MSM in R ha una funzione, rtnorm, che calcola i disegni da un troncato normale. Il pacchetto truncnorm in R ha anche funzioni per trarre da una normale troncata.


Guardandosi intorno, molto di questo è trattato nelle risposte ad altre domande (ma non esattamente duplicati poiché questa domanda è più generale del normale troncato) … vedere la discussione aggiuntiva in

a. Questa risposta

b. Xi “an” s answer qui , che contiene un link al suo articolo arXiv (insieme ad altre risposte utili).

Risposta

Lapproccio rapido e sporco consiste nellutilizzare la regola 68-95-99.7 .

In una distribuzione normale, il 99,7% dei valori rientra in 3 deviazioni standard della media. Quindi, se imposti la media al centro del valore minimo e massimo desiderati e imposti la deviazione standard a 1/3 della tua media, ottieni (principalmente) valori che rientrano nellintervallo desiderato. Quindi puoi semplicemente ripulire il resto.

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) 

Di recente ho riscontrato lo stesso problema, cercando di generare voti degli studenti casuali per i dati dei test. Nel codice sopra, ho “utilizzato pmax e pmin per sostituire i valori fuori dai limiti con i limiti minimi o massimi valore.Funziona per il mio scopo, perché sto generando quantità di dati piuttosto piccole, ma per quantità maggiori ti darà notevoli sbalzi sui valori minimo e massimo. Quindi, a seconda dei tuoi scopi, potrebbe essere meglio scartare quei valori, sostituirli con NA s, o “ripeti il rollio” finché “non rientrano nei limiti.

Commenti

  • Perché preoccuparsi di farlo? È così semplice generare numeri casuali normali e rilasciare quelli che necessitano di troncamento che non è ‘ necessario complicarsi a meno che il troncamento desiderato non sia vicino al 100% dellarea della densità.
  • Forse ‘ sto interpretando male la domanda originale. Mi sono imbattuto in questa domanda mentre cercavo di capire come ottenere unattività di programmazione non correlata direttamente alle statistiche in R e ‘ ho notato solo ora che questa pagina è uno scambio di statistiche , non uno stackexchange di programmazione. 🙂 Nel mio caso, volevo generare una quantità specifica di numeri interi casuali, con valori compresi tra 0 e 100, e volevo che i valori generati cadessero su una bella curva a campana su quellintervallo. Da quando ho scritto questo, ‘ mi sono reso conto che sample(x=min:max, prob=dnorm(...)) è forse un modo più semplice per farlo.
  • @Glen_b Aaron Wells menziona sample(x=min:max, prob=dnorm(...)) che sembra un po più breve della tua risposta.
  • Ma tieni presente che il sample() trucco è utile solo se ‘ stai tentando di scegliere numeri interi casuali o qualche altro insieme di valori predefiniti distinti.

Rispondi

Nessuna delle risposte qui fornisce un metodo efficiente per generare variabili normali troncate che non implicano il rifiuto di variabili arbitrariamente grandi numero di valori generati. Se desideri generare valori da una distribuzione normale troncata, con limiti inferiore e superiore specificati $ a < b $ , questo può essere fatto — senza rigetto — generando quantili uniformi nellintervallo di quantili consentito dal troncamento e utilizzando il campionamento della trasformazione inversa per ottenere i corrispondenti valori normali .

Sia $ \ Phi $ il CDF della distribuzione normale standard. Vogliamo generare $ X_1, …, X_N $ da una distribuzione normale troncata (con parametro medio $ \ mu $ e il parametro di varianza $ \ sigma ^ 2 $ ) $ ^ \ dagger $ con lettere minuscole e limiti di troncamento superiori $ a < b $ . Questo può essere fatto come segue:

$$ 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]. $$

Non esiste una funzione incorporata per i valori generati dalla distribuzione troncata, ma è banale programmare questo metodo usando il funzioni ordinarie per la generazione di variabili casuali. Ecco una semplice R funzione rtruncnorm che implementa questo metodo in poche righe di codice.

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); } 

Questa è una funzione vettorizzata che genererà N variabili casuali IID dalla distribuzione normale troncata. Sarebbe facile programmare funzioni per altre distribuzioni troncate tramite lo stesso metodo. Inoltre non sarebbe troppo difficile programmare le funzioni di densità e quantile associate per la distribuzione troncata.


$ ^ \ dagger $ Nota che il troncamento altera la media e la varianza della distribuzione, quindi $ \ mu $ e $ \ sigma ^ 2 $ sono non media e varianza della distribuzione troncata.

Risposta

Per me tre modi hanno funzionato:

  1. utilizzando sample () con rnorm ():

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

  2. utilizzando il pacchetto msm e la funzione rtnorm:

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

  3. utilizzando rnorm () e specificando i limiti inferiore e superiore, come Hugh ha postato sopra:

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

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *