Wie kann ich eine gleichmäßige Verteilung (wie die meisten Zufallszahlengeneratoren beispielsweise zwischen 0,0 und 1,0 erzeugen) in eine Normalverteilung umwandeln? Was ist, wenn ich einen Mittelwert und eine Standardabweichung meiner Wahl möchte?
Wie kann ich eine gleichmäßige Verteilung (wie die meisten Zufallszahlengeneratoren beispielsweise zwischen 0,0 und 1,0 erzeugen) in eine Normalverteilung umwandeln? Was ist, wenn ich einen Mittelwert und eine Standardabweichung meiner Wahl möchte?
Antworten:
Der Ziggurat-Algorithmus ist dafür ziemlich effizient, obwohl die Box-Muller-Transformation einfacher von Grund auf neu zu implementieren ist (und nicht verrückt langsam).
Es gibt viele Methoden:
Um die Verteilung einer Funktion auf eine andere zu ändern, müssen Sie die Umkehrung der gewünschten Funktion verwenden.
Mit anderen Worten, wenn Sie eine bestimmte Wahrscheinlichkeitsfunktion p (x) anstreben, erhalten Sie die Verteilung, indem Sie darüber integrieren -> d (x) = Integral (p (x)) und deren Umkehrung verwenden: Inv (d (x)) . Verwenden Sie nun die Zufallswahrscheinlichkeitsfunktion (die gleichmäßig verteilt ist) und wandeln Sie den Ergebniswert durch die Funktion Inv (d (x)). Sie sollten zufällige Werte erhalten, die entsprechend der von Ihnen gewählten Funktion verteilt werden.
Dies ist der generische mathematische Ansatz. Wenn Sie ihn verwenden, können Sie jetzt jede Wahrscheinlichkeits- oder Verteilungsfunktion auswählen, die Sie haben, solange sie eine inverse oder gute inverse Approximation hat.
Hoffe das hat geholfen und danke für die kleine Bemerkung zur Verwendung der Distribution und nicht der Wahrscheinlichkeit selbst.
Hier ist eine Javascript-Implementierung unter Verwendung der polaren Form der Box-Muller-Transformation.
/*
* Returns member of set with a given mean and standard deviation
* mean: mean
* standard deviation: std_dev
*/
function createMemberInNormalDistribution(mean,std_dev){
return mean + (gaussRandom()*std_dev);
}
/*
* Returns random number in normal distribution centering on 0.
* ~95% of numbers returned should fall between -2 and 2
* ie within two standard deviations
*/
function gaussRandom() {
var u = 2*Math.random()-1;
var v = 2*Math.random()-1;
var r = u*u + v*v;
/*if outside interval [0,1] start over*/
if(r == 0 || r >= 1) return gaussRandom();
var c = Math.sqrt(-2*Math.log(r)/r);
return u*c;
/* todo: optimize this algorithm by caching (v*c)
* and returning next time gaussRandom() is called.
* left out for simplicity */
}
Verwenden Sie den zentralen Grenzwertsatz Wikipedia-Eintrag Mathworld-Eintrag zu Ihrem Vorteil.
Generieren Sie n der gleichmäßig verteilten Zahlen, summieren Sie sie, subtrahieren Sie n * 0,5 und Sie haben die Ausgabe einer ungefähr normalen Verteilung mit einem Mittelwert von 0 und einer Varianz von (1/12) * (1/sqrt(N))
(siehe Wikipedia zu gleichmäßigen Verteilungen für die letzte).
n = 10 gibt dir schnell etwas halbwegs Anständiges. Wenn Sie etwas mehr als halbwegs Anständiges wollen, entscheiden Sie sich für eine Tyler-Lösung (wie im Wikipedia-Eintrag zu Normalverteilungen angegeben ).
Ich würde Box-Muller benutzen. Zwei Dinge dazu:
Wobei R1, R2 zufällige einheitliche Zahlen sind:
NORMALE VERTEILUNG mit SD von 1: sqrt (-2 * log (R1)) * cos (2 * pi * R2)
Das ist genau ... Sie müssen nicht all diese langsamen Schleifen machen!
Es scheint unglaublich, dass ich nach acht Jahren noch etwas hinzufügen könnte, aber für den Fall von Java möchte ich die Leser auf die Random.nextGaussian () -Methode verweisen , die für Sie eine Gaußsche Verteilung mit einem Mittelwert von 0,0 und einer Standardabweichung von 1,0 generiert.
Eine einfache Addition und / oder Multiplikation ändert den Mittelwert und die Standardabweichung an Ihre Bedürfnisse.
Dies ist meine JavaScript-Implementierung von Algorithmus P ( Polar-Methode für normale Abweichungen ) aus Abschnitt 3.4.1 von Donald Knuths Buch The Art of Computer Programming :
function normal_random(mean,stddev)
{
var V1
var V2
var S
do{
var U1 = Math.random() // return uniform distributed in [0,1[
var U2 = Math.random()
V1 = 2*U1-1
V2 = 2*U2-1
S = V1*V1+V2*V2
}while(S >= 1)
if(S===0) return 0
return mean+stddev*(V1*Math.sqrt(-2*Math.log(S)/S))
}
Das Standard-Python-Bibliotheksmodul random hat das, was Sie wollen:
Normalvariable (mu, Sigma)
Normalverteilung. mu ist der Mittelwert und Sigma ist die Standardabweichung.
Schauen Sie sich für den Algorithmus selbst die Funktion in random.py in der Python-Bibliothek an.
Ich denke, Sie sollten dies in EXCEL versuchen : =norminv(rand();0;1)
. Dies ergibt die Zufallszahlen, die normalerweise mit dem Mittelwert Null verteilt werden sollen, und vereint die Varianz. "0" kann mit einem beliebigen Wert angegeben werden, so dass die Zahlen den gewünschten Mittelwert haben. Durch Ändern von "1" erhalten Sie die Varianz, die dem Quadrat Ihrer Eingabe entspricht.
Zum Beispiel: =norminv(rand();50;3)
ergibt die normalverteilten Zahlen mit MEAN = 50 VARIANCE = 9.
F Wie kann ich eine Gleichverteilung (wie die meisten Zufallszahlengeneratoren, z. B. zwischen 0,0 und 1,0) in eine Normalverteilung umwandeln?
Für die Software-Implementierung kenne ich einige zufällige Generatornamen, die Ihnen eine pseudo-einheitliche zufällige Sequenz in [0,1] geben (Mersenne Twister, Linear Congruate Generator). Nennen wir es U (x)
Es gibt einen mathematischen Bereich, der Wahrscheinlichkeitstheorie genannt wird. Das erste: Wenn Sie rv mit der Integralverteilung F modellieren möchten, können Sie versuchen, nur F ^ -1 (U (x)) auszuwerten. In der Theorie wurde bewiesen, dass ein solches RV eine integrale Verteilung F haben wird.
Schritt 2 kann angewendet werden, um rv ~ F ohne Verwendung von Zählmethoden zu erzeugen, wenn F ^ -1 ohne Probleme analytisch abgeleitet werden kann. (zB exp.distribution)
Um die Normalverteilung zu modellieren, können Sie y1 * cos (y2) berechnen, wobei y1 ~ in [0,2pi] einheitlich ist. und y2 ist die relei Verteilung.
F: Was ist, wenn ich einen Mittelwert und eine Standardabweichung meiner Wahl möchte?
Sie können Sigma * N (0,1) + m berechnen.
Es kann gezeigt werden, dass eine solche Verschiebung und Skalierung zu N (m, Sigma) führt.
Dies ist eine Matlab-Implementierung, die die polare Form der Box-Muller- Transformation verwendet:
Funktion randn_box_muller.m
:
function [values] = randn_box_muller(n, mean, std_dev)
if nargin == 1
mean = 0;
std_dev = 1;
end
r = gaussRandomN(n);
values = r.*std_dev - mean;
end
function [values] = gaussRandomN(n)
[u, v, r] = gaussRandomNValid(n);
c = sqrt(-2*log(r)./r);
values = u.*c;
end
function [u, v, r] = gaussRandomNValid(n)
r = zeros(n, 1);
u = zeros(n, 1);
v = zeros(n, 1);
filter = r==0 | r>=1;
% if outside interval [0,1] start over
while n ~= 0
u(filter) = 2*rand(n, 1)-1;
v(filter) = 2*rand(n, 1)-1;
r(filter) = u(filter).*u(filter) + v(filter).*v(filter);
filter = r==0 | r>=1;
n = size(r(filter),1);
end
end
Und dies aufzurufen histfit(randn_box_muller(10000000),100);
ist das Ergebnis:
Offensichtlich ist es im Vergleich zum eingebauten Matlab- Randn wirklich ineffizient .
Ich habe den folgenden Code, der vielleicht helfen könnte:
set.seed(123)
n <- 1000
u <- runif(n) #creates U
x <- -log(u)
y <- runif(n, max=u*sqrt((2*exp(1))/pi)) #create Y
z <- ifelse (y < dnorm(x)/2, -x, NA)
z <- ifelse ((y > dnorm(x)/2) & (y < dnorm(x)), x, z)
z <- z[!is.na(z)]
Es ist auch einfacher, die implementierte Funktion rnorm () zu verwenden, da sie schneller ist als das Schreiben eines Zufallszahlengenerators für die Normalverteilung. Siehe den folgenden Code als Beweis
n <- length(z)
t0 <- Sys.time()
z <- rnorm(n)
t1 <- Sys.time()
t1-t0
function distRandom(){
do{
x=random(DISTRIBUTION_DOMAIN);
}while(random(DISTRIBUTION_RANGE)>=distributionFunction(x));
return x;
}