Genera numeri casuali seguendo una distribuzione all'interno di un intervallo


17

Devo generare numeri casuali dopo la distribuzione normale nell'intervallo . (Sto lavorando in R.)(un',B)

So che la funzione rnorm(n,mean,sd)genererà numeri casuali dopo la normale distribuzione, ma come impostare i limiti di intervallo all'interno di quello? Sono disponibili funzioni R particolari per questo?


Perchè vuoi fare questo? Se è limitato, non può essere davvero normale. Cosa stai cercando di ottenere?
gung - Ripristina Monica

x <- rnorm(n, mean, sd); x <- x[x > lower.limit & x < upper.limit]
Hugh,

3
@Hugh è fantastico ... purché non ti interessi quanti valori casuali ottieni.
Glen_b -Restate Monica,

Risposte:


31

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

Esistono diversi metodi per farlo, alcuni semplici, altri relativamente efficienti.

Illustrerò alcuni approcci sul tuo esempio normale.

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

    repeun't generaXio da N (media, sd)untiol inferioreXio superiore

    inserisci qui la descrizione dell'immagine

    Se la maggior parte della distribuzione rientra nei limiti, questo è abbastanza ragionevole, ma può diventare piuttosto lento se si genera quasi sempre al di fuori dei limiti.

    In R potresti evitare il ciclo uno alla volta calcolando l'area entro i limiti e generare abbastanza valori che potresti essere quasi certo che dopo aver buttato fuori i valori fuori dai limiti avessi ancora tutti i valori necessari.

  2. È possibile utilizzare Accetta-Rifiuta con alcune funzioni di potenziamento adeguate nell'intervallo (in alcuni casi l'uniforme sarà abbastanza buona). Se i limiti fossero ragionevolmente stretti rispetto allo sd ma non fossi lontano dalla coda, un maggioramento uniforme funzionerebbe bene con il normale, per esempio.

    inserisci qui la descrizione dell'immagine

  3. Se hai un cdf ragionevolmente efficiente e un cdf inverso (come pnorme qnormper la normale distribuzione in R) puoi usare il metodo inverse-cdf descritto nel primo paragrafo della sezione di simulazione della pagina di Wikipedia sulla normale troncata . [In effetti, questo equivale a prendere un'uniforme troncata (troncata nei quantili richiesti, che in realtà non richiede alcun rifiuto, dal momento che è solo un'altra uniforme) e applicare il normale cdf inverso a quello. Nota che questo può fallire se sei lontano nella coda]

    inserisci qui la descrizione dell'immagine

  4. Ci sono altri approcci; la stessa pagina di Wikipedia menziona l'adattamento del metodo ziggurat , che dovrebbe funzionare per una varietà di distribuzioni.

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

Il MSMpacchetto in R ha una funzione rtnorm, che calcola i disegni da una normale troncata. Il truncnormpacchetto in R ha anche funzioni da trarre da una normale troncata.


Guardandosi intorno, gran parte di questo è coperto dalle risposte ad altre domande (ma non esattamente dai duplicati poiché questa domanda è più generale del normale troncato) ... vedi ulteriori discussioni in

un. Questa risposta

b. La risposta di Xi'an qui , che ha un link al suo articolo arXiv (insieme ad altre risposte utili).


2

L'approccio rapido è usare la regola 68-95-99.7 .

In una distribuzione normale, il 99,7% dei valori rientra in 3 deviazioni standard della media. Pertanto, se si imposta la media al centro del valore minimo e del valore massimo desiderati e si imposta la deviazione standard su 1/3 della media, si ottengono (principalmente) valori che rientrano nell'intervallo 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 affrontato lo stesso problema, cercando di generare voti casuali per gli studenti per i dati dei test. Nel codice sopra, ho usato pmaxe pminper sostituire i valori fuori limite con il valore minimo o massimo entro i limiti. Questo funziona per il mio scopo, perché sto generando quantità piuttosto piccole di dati, ma per quantità maggiori ti darà notevoli rilievi ai valori minimo e massimo. Quindi, a seconda dei tuoi scopi, potrebbe essere meglio scartare quei valori, sostituirli con NAs o "rilanciarli" fino a quando non sono in-bound.


Perché preoccuparsi di farlo? È così semplice generare normali numeri casuali e rilasciare quelli che necessitano di troncamento che non è necessario essere complicati al riguardo a meno che il troncamento desiderato non sia vicino al 100% dell'area della densità.
Carl

2
Forse sto interpretando male la domanda originale. Mi sono imbattuto in questa domanda mentre cercavo di capire come realizzare un'attività di programmazione non direttamente correlata alle statistiche in R, e solo ora ho notato che questa pagina è uno scambio di statistiche, non uno scambio 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 in quell'intervallo. Da quando ho scritto questo ho capito che sample(x=min:max, prob=dnorm(...))forse è un modo più semplice per farlo.
Aaron Wells,

@Glen_b menziona Aaron Wells sample(x=min:max, prob=dnorm(...))che sembra un po 'più breve della tua risposta.
Carl,

Ma nota che il sample()trucco è utile solo se stai cercando di scegliere numeri casuali o qualche altro insieme di valori predefiniti discreti.
Aaron Wells,

1

un'<B

ΦX1,...,XNμσ2un'<B

Xio=μ+σΦ-1(Uio)U1,...,UN~IID U[Φ(un'-μσ),Φ(B-μσ)].

Non esiste una funzione integrata per i valori generati dalla distribuzione troncata, ma è banale programmare questo metodo usando le normali funzioni per generare variabili casuali. Ecco una semplice Rfunzione rtruncnormche 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 vettoriale che genererà Nvariabili casuali IID dalla distribuzione normale troncata. Sarebbe facile programmare le funzioni per altre distribuzioni troncate con lo stesso metodo. Inoltre, non sarebbe troppo difficile programmare la densità e le funzioni quantiche associate per la distribuzione troncata.


μσ2

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.