Ich muss Zufallszahlen nach der Normalverteilung innerhalb des Intervalls $ (a, b) $ generieren. (Ich arbeite in R.)
Ich weiß, dass die Funktion rnorm(n,mean,sd)
Zufallszahlen nach der Normalverteilung generiert, aber wie werden die Intervallgrenzen innerhalb dieser festgelegt? Gibt es dafür bestimmte R-Funktionen?
Kommentare
- Warum möchten Sie dies tun? Wenn es ‚ begrenzt ist, kann es ‚ nicht wirklich normal sein. Was möchten Sie erreichen?
-
x <- rnorm(n, mean, sd); x <- x[x > lower.limit & x < upper.limit]
- @Hugh, dass ‚ großartig ist … solange Sie ‚ nicht interessieren, wie viele zufällige Werte Sie erhalten.
Antwort
Es hört sich so an, als ob Sie aus einer abgeschnittenen Verteilung und in Ihrem speziellen Beispiel simulieren möchten , a abgeschnittenes normales .
Hierfür gibt es verschiedene Methoden, einige einfache, andere relativ effizient.
Ich werde einige Ansätze an Ihrem normalen Beispiel veranschaulichen.
-
Hier ist eine sehr einfache Methode zum Generieren eines nach dem anderen (in einer Art Pseudocode) ):
$ \ tt {repeat} $ generiere $ x_i $ aus N. (mean, sd) $ \ tt {bis} $ unter $ \ leq x_i \ leq $ ober
Wenn der größte Teil der Verteilung innerhalb der Grenzen liegt, ist dies ziemlich vernünftig, kann aber recht langsam werden, wenn Sie generieren fast immer außerhalb der Grenzen.
In R können Sie die Einzelschleife vermeiden, indem Sie den Bereich innerhalb der Grenzen berechnen und genügend Werte generieren, von denen Sie nach dem Auswerfen fast sicher sein können Die Werte außerhalb der Grenzen hatten immer noch so viele Werte wie nötig.
-
Sie können Accept-Reject mit einer geeigneten Majorisierungsfunktion über das Intervall verwenden (in einigen Fällen einheitlicher Wille) gut genug sein). Wenn die Grenzen im Verhältnis zum s.d. Aber Sie waren nicht weit im Schwanz, eine einheitliche Majorisierung würde zum Beispiel mit dem Normalen gut funktionieren.
-
Wenn Sie ein einigermaßen effizientes cdf und ein inverses cdf haben (z. B.
pnorm
undqnorm
für das Normalverteilung in R) Sie können die inverse-cdf-Methode verwenden, die im ersten Absatz des Simulationsabschnitts von der Wikipedia-Seite auf der abgeschnittenen Normalen beschrieben ist Dies ist dasselbe, als würde man eine abgeschnittene Uniform (abgeschnitten bei den erforderlichen Quantilen, was eigentlich überhaupt keine Zurückweisung erfordert, da dies nur eine weitere Uniform ist) nehmen und das inverse normale cdf darauf anwenden. Beachten Sie, dass dies fehlschlagen kann, wenn Sie „weit im Schwanz sind] -
Es gibt andere Ansätze: Auf derselben Wikipedia-Seite wird die Anpassung der Zikkurat -Methode erwähnt, die für eine Vielzahl von Distributionen funktionieren sollte.
Der gleiche Wikipedia-Link erwähnt zwei spezifische Pakete (beide auf CRAN) mit Funktionen zum Generieren abgeschnittener Normalen:
Das
MSM
-Paket in R hat die Funktionrtnorm
, die Ziehungen aus einem abgeschnittenen berechnet normal. Das Pakettruncnorm
in R verfügt auch über Funktionen zum Zeichnen aus einer abgeschnittenen Normalen.
Wenn Sie sich umschauen, wird vieles davon in Antworten auf andere Fragen behandelt (aber nicht genau in Duplikaten, da diese Frage allgemeiner ist als nur die abgeschnittene Normalfrage) … siehe zusätzliche Diskussion in
a. Diese Antwort
b. Xi „an“ s Antwort hier , die einen Link zu seinem arXiv-Artikel enthält (zusammen mit einigen anderen wertvollen Antworten).
Antwort
Der schnelle und schmutzige Ansatz besteht darin, die 68-95-99.7-Regel .
Bei einer Normalverteilung liegen 99,7% der Werte innerhalb von 3 Standardabweichungen vom Mittelwert. Wenn Sie also Ihren Mittelwert auf die Mitte Ihres gewünschten Minimal- und Maximalwerts setzen und Ihre Standardabweichung auf 1/3 Ihres Mittelwerts setzen, erhalten Sie (meistens) Werte, die innerhalb des gewünschten Intervalls liegen. Dann können Sie einfach den Rest bereinigen.
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)
Ich hatte kürzlich das gleiche Problem und versuchte, zu generieren zufällige Noten für Testdaten. Im obigen Code habe ich pmax
und pmin
verwendet, um Werte außerhalb der Grenzen durch die minimalen oder maximalen Werte zu ersetzen Wert.Dies funktioniert für meinen Zweck, da ich relativ kleine Datenmengen generiere, bei größeren Mengen jedoch bei den Min- und Max-Werten spürbare Unebenheiten auftreten. Abhängig von Ihren Zwecken ist es möglicherweise besser, diese Werte zu verwerfen und zu ersetzen mit NA
s oder „re-roll“ sie, bis sie „in-bounds“ sind.
Kommentare
- Warum sich die Mühe machen, das zu tun? Es ist so einfach, normale Zufallszahlen zu generieren und diejenigen zu löschen, die abgeschnitten werden müssen, dass es nicht ‚ erforderlich ist, dies zu komplizieren, es sei denn, die gewünschte Kürzung liegt nahe bei 100% der Fläche der Dichte.
- Vielleicht habe ich ‚ die ursprüngliche Frage falsch interpretiert. Ich bin auf diese Frage gestoßen, als ich versucht habe, herauszufinden, wie eine nicht direkt auf Statistiken bezogene Programmieraufgabe in R ausgeführt werden kann, und ‚ habe erst jetzt bemerkt, dass diese Seite ein Statistik-Stapelaustausch ist , kein Programmierstapelaustausch. 🙂 In meinem Fall wollte ich eine bestimmte Anzahl zufälliger Ganzzahlen mit Werten zwischen 0 und 100 generieren, und ich wollte, dass die generierten Werte über diesen Bereich auf eine schöne Glockenkurve fallen. Seit ich dies geschrieben habe, habe ich ‚ erkannt, dass
sample(x=min:max, prob=dnorm(...))
möglicherweise ein einfacher Weg ist, dies zu tun. - @Glen_b Aaron Wells erwähnt
sample(x=min:max, prob=dnorm(...))
, was etwas kürzer als Ihre Antwort zu sein scheint. - Beachten Sie jedoch, dass der Trick
sample()
nur nützlich ist Wenn Sie ‚ versuchen, zufällige Ganzzahlen oder einen anderen Satz diskreter, vordefinierter Werte auszuwählen.
Antwort
Keine der Antworten hier bietet eine effiziente Methode zum Generieren von abgeschnittenen normalen Variablen, bei denen keine beliebig großen abgelehnt werden Anzahl der generierten Werte. Wenn Sie Werte aus einer abgeschnittenen Normalverteilung mit angegebenen unteren und oberen Grenzen $ a < b $ generieren möchten, ist dies der Fall kann — ohne Zurückweisung — durchgeführt werden, indem einheitliche Quantile über den durch die Kürzung zulässigen Quantilbereich erzeugt werden und inverse Transformationsabtastung verwendet wird, um entsprechende Normalwerte zu erhalten
Lassen Sie $ \ Phi $ die CDF der Standardnormalverteilung bezeichnen. Wir wollen $ X_1, …, X_N $ aus einer abgeschnittenen Normalverteilung generieren (mit dem mittleren Parameter $ \ mu $ und Varianzparameter $ \ sigma ^ 2 $ ) $ ^ \ dagger $ mit niedrigerem und obere Kürzungsgrenzen $ a < b $ . Dies kann wie folgt erfolgen:
$$ 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]. $$
Es gibt keine eingebaute Funktion für generierte Werte aus der abgeschnittenen Verteilung, aber es ist trivial, diese Methode mit der zu programmieren gewöhnliche Funktionen zum Erzeugen von Zufallsvariablen. Hier ist eine einfache R
-Funktion rtruncnorm
, die diese Methode in wenigen Codezeilen implementiert.
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); }
Dies ist eine vektorisierte Funktion, die N
IID-Zufallsvariablen aus der abgeschnittenen Normalverteilung generiert. Es wäre einfach, Funktionen für andere abgeschnittene Verteilungen mit derselben Methode zu programmieren. Es wäre auch nicht allzu schwierig, zugehörige Dichte- und Quantilfunktionen für die abgeschnittene Verteilung zu programmieren.
$ ^ \ dagger $ Beachten Sie, dass Die Kürzung ändert den Mittelwert und die Varianz der Verteilung, also $ \ mu $ und $ \ sigma ^ 2 $ sind nicht der Mittelwert und die Varianz der abgeschnittenen Verteilung.
Antwort
Drei Möglichkeiten haben bei mir funktioniert:
-
Verwenden von sample () mit rnorm ():
sample(x=min:max, replace= TRUE, rnorm(n, mean))
-
unter Verwendung des msm-Pakets und der rtnorm-Funktion:
rtnorm(n, mean, lower=min, upper=max)
-
unter Verwendung von rnorm () und Angabe der unteren und oberen Grenzen, wie Hugh oben angegeben hat:
sample <- rnorm(n, mean=mean); sample <- sample[x > min & x < max]