Generieren Sie Zufallszahlen nach einer Verteilung innerhalb eines Intervalls

17

Ich muss Zufallszahlen generieren, die der Normalverteilung innerhalb des Intervalls folgen . (Ich arbeite in R.)(a,b)

Ich weiß, dass die Funktion rnorm(n,mean,sd)nach der Normalverteilung Zufallszahlen generiert, aber wie werden die Intervallgrenzen innerhalb dieser Funktion festgelegt? Gibt es dafür spezielle R-Funktionen?

dvs
quelle
Warum willst du das machen? Wenn es begrenzt ist, kann es nicht wirklich normal sein. Was versuchst du zu erreichen?
gung - Wiedereinsetzung von Monica
x <- rnorm(n, mean, sd); x <- x[x > lower.limit & x < upper.limit]
Hugh
3
@Hugh, das ist großartig ... solange es dir egal ist, wie viele zufällige Werte du erhältst.
Glen_b -Reinstate Monica

Antworten:

31

Es hört sich so an, als ob Sie eine abgeschnittene Verteilung und in Ihrem speziellen Beispiel eine abgeschnittene Normalverteilung simulieren möchten .

Es gibt eine Vielzahl von Methoden, einige einfache, andere relativ effiziente.

Ich werde einige Ansätze an Ihrem normalen Beispiel veranschaulichen.

  1. Hier ist eine sehr einfache Methode, um einen nach dem anderen zu generieren (in einer Art Pseudocode):

    repeat generiere aus N (mean, sd) lower upperxiuntilxi

    Bildbeschreibung hier eingeben

    Wenn der Großteil der Distribution innerhalb der Grenzen liegt, ist dies ziemlich vernünftig, aber es kann ziemlich langsam werden, wenn Sie fast immer außerhalb der Grenzen generieren.

    In R können Sie die einzelne Schleife vermeiden, indem Sie den Bereich innerhalb der Grenzen berechnen und so viele Werte generieren, dass Sie fast sicher sein können, dass Sie nach dem Wegwerfen der Werte außerhalb der Grenzen immer noch so viele Werte wie nötig hatten.

  2. Sie können Accept-Reject mit einer geeigneten Majorizing-Funktion über das Intervall verwenden (in einigen Fällen ist Uniform ausreichend). Wenn die Grenzen relativ zum SD relativ eng wären, Sie aber nicht weit im Heck stecken, würde eine einheitliche Majorisierung zum Beispiel mit dem Normalen gut funktionieren.

    Bildbeschreibung hier eingeben

  3. Wenn Sie eine einigermaßen effiziente cdf- und inverse cdf-Datei haben (z. B. pnormund qnormfür die Normalverteilung in R), können Sie die inverse cdf-Methode verwenden, die im ersten Absatz des Simulationsabschnitts der Wikipedia-Seite für die abgeschnittene Normalen beschrieben ist . [Tatsächlich ist dies dasselbe, als würde man eine abgeschnittene Uniform nehmen (abgeschnitten auf die erforderlichen Quantile, für die eigentlich überhaupt keine Ablehnung erforderlich ist, da dies nur eine weitere Uniform ist) und darauf die inverse normale cdf anwenden. Beachten Sie, dass dies fehlschlagen kann, wenn Sie weit im Heck sind.]

    Bildbeschreibung hier eingeben

  4. Es gibt andere Ansätze; Die gleiche Wikipedia-Seite erwähnt die Anpassung der Zikkurat- Methode, die für eine Vielzahl von Distributionen funktionieren sollte.

Die gleichen Empfehlungen erwähnt zwei spezifische Pakete (beide auf CRAN) mit Funktionen zur Erzeugung von Normalen trunkiert:

Das MSMPaket in R hat eine Funktion rtnorm, die Draws aus einer abgeschnittenen Normalen berechnet. Das truncnormPaket in R hat auch Funktionen zum Zeichnen aus einer abgeschnittenen Normalen.


Wenn Sie sich umschauen, wird vieles davon in Antworten auf andere Fragen behandelt (aber nicht genau doppelt, da diese Frage allgemeiner ist als nur die abgeschnittene Norm) ... siehe zusätzliche Diskussion in

ein. Diese Antwort

b. Xi'ans Antwort hier , die einen Link zu seinem Artikel von arXiv enthält (zusammen mit einigen anderen nützlichen Antworten).

Glen_b - Setzen Sie Monica wieder ein
quelle
2

Der schnelle und schmutzige Ansatz besteht darin, die 68-95-99.7-Regel zu verwenden .

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 einstellen und Ihre Standardabweichung auf 1/3 Ihres Mittelwerts einstellen, erhalten Sie (meistens) Werte, die innerhalb des gewünschten Intervalls liegen. Dann können Sie einfach den Rest aufräumen.

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)

Vor kurzem war ich mit demselben Problem konfrontiert, als ich versuchte, zufällige Noten für Testdaten zu generieren . Im obigen Code habe ich Grenzüberschreitungswerte verwendet pmaxund pmindurch den Grenzüberschreitungswert "min" oder "max" ersetzt. Dies funktioniert für meinen Zweck, da ich relativ kleine Datenmengen generiere, bei größeren Datenmengen jedoch spürbare Unebenheiten bei den Min- und Max-Werten auftreten. Abhängig von Ihren Zwecken ist es daher möglicherweise besser, diese Werte zu verwerfen, durch NAs zu ersetzen oder sie neu zu würfeln, bis sie eingegrenzt sind.

Aaron Wells
quelle
Warum sollte ich das tun? Es ist so einfach, normale Zufallszahlen zu generieren und diejenigen zu löschen, die abgeschnitten werden müssen, dass es nicht erforderlich ist, kompliziert zu sein, es sei denn, die gewünschte Abschneidung entspricht nahezu 100% der Fläche der Dichte.
Carl
2
Vielleicht interpretiere ich die ursprüngliche Frage falsch. Ich bin auf diese Frage gestoßen, als ich versucht habe, herauszufinden, wie eine nicht direkt mit Statistiken in Zusammenhang stehende Programmieraufgabe in R ausgeführt werden kann, und habe erst jetzt bemerkt, dass es sich bei dieser Seite um einen Statistikstapelaustausch und nicht um einen Programmierstapelaustausch handelt. :) 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 schreibe, sample(x=min:max, prob=dnorm(...))ist mir klar geworden, dass dies vielleicht ein einfacher Weg ist.
Aaron Wells
@ Glen_b Aaron Wells erwähnt, sample(x=min:max, prob=dnorm(...))was etwas kürzer zu sein scheint als Ihre Antwort.
Carl
Beachten Sie jedoch, dass der sample()Trick nur nützlich ist, wenn Sie versuchen, zufällige Ganzzahlen oder einen anderen Satz diskreter vordefinierter Werte auszuwählen.
Aaron Wells
1

a<b

Lassen Sie ΦX1,...,XNμσ2a<b

Xi=μ+σΦ1(Ui)U1,...,UNIID U[Φ(aμσ),Φ(bμσ)].

Es gibt keine eingebaute Funktion für generierte Werte aus der abgeschnittenen Verteilung, aber es ist trivial, diese Methode mit den üblichen Funktionen zum Generieren von Zufallsvariablen zu programmieren. Hier ist eine einfache RFunktion 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 NIID-Zufallsvariablen aus der abgeschnittenen Normalverteilung generiert . Es wäre einfach, Funktionen für andere verkürzte Verteilungen mit derselben Methode zu programmieren. Es wäre auch nicht zu schwierig, zugehörige Dichte- und Quantilfunktionen für die abgeschnittene Verteilung zu programmieren.


μσ2

Setzen Sie Monica wieder ein
quelle