Ich möchte nur ein mathematisches Ergebnis hinzufügen, das für Normalverteilungen (aufgrund komplexer CDF) nicht sofort nützlich ist, aber für viele andere Verteilungen nützlich ist. Wenn Sie gleichmäßig verteilte Zufallszahlen in [0,1] (mit Random.NextDouble()) in die Umkehrung der CDF JEDER Verteilung einfügen, erhalten Sie Zufallszahlen, die DIESER Verteilung folgen. Wenn Ihre Anwendung keine genau normalverteilten Variablen benötigt, ist die logistische Verteilung eine sehr enge Annäherung an die normale und verfügt über eine leicht invertierbare CDF.
Ozzah
1
Das MedallionRandom NuGet-Paket enthält eine Erweiterungsmethode zum Abrufen normalverteilter Werte aus einer Randommithilfe der Box-Muller-Transformation (in den folgenden Antworten unten erwähnt).
ChaseMedallion
Antworten:
180
Jarretts Vorschlag, eine Box-Muller-Transformation zu verwenden, ist gut für eine schnelle und schmutzige Lösung. Eine einfache Implementierung:
Random rand =newRandom();//reuse this if you are generating manydouble u1 =1.0-rand.NextDouble();//uniform(0,1] random doublesdouble u2 =1.0-rand.NextDouble();double randStdNormal =Math.Sqrt(-2.0*Math.Log(u1))*Math.Sin(2.0*Math.PI * u2);//random normal(0,1)double randNormal =
mean + stdDev * randStdNormal;//random normal(mean,stdDev^2)
Ich habe es getestet und mit MathNets Mersenne Twister RNG und NormalDistribution verglichen. Ihre Version ist mehr als doppelt so schnell und das Endergebnis ist im Grunde das gleiche (visuelle Überprüfung der "Glocken").
Johann Gerell
4
@Johann, wenn Sie reine Geschwindigkeit suchen, dann wird der Zigorat-Algorithmus allgemein als der schnellste Ansatz anerkannt. Darüber hinaus kann der obige Ansatz beschleunigt werden, indem ein Wert von einem Anruf zum nächsten übertragen wird.
Drew Noakes
Hallo, auf was soll die stdDevVariable gesetzt werden? Ich verstehe, dass dies für bestimmte Anforderungen konfiguriert werden kann, aber gibt es irgendwelche Grenzen (dh Max / Min-Werte)?
Hofnarwillie
@hofnarwillie stdDev ist der Skalierungsparameter der Normalverteilung, der eine beliebige positive Zahl sein kann. Je größer es ist, desto zerstreuter werden die generierten Zahlen sein. Verwenden Sie für eine Standardnormalverteilung die Parameter mean = 0 und stdDev = 1.
Yoyoyoyosef
1
@ Jack Ich glaube nicht. Nur das -2 * Math.Log (u1) befindet sich innerhalb des sqrt, und das Protokoll ist immer negativ oder null, da u1 <= 1
yoyoyoyosef
62
Diese Frage scheint über Google für die .NET-Gauß-Generation zu stehen, daher dachte ich, ich würde eine Antwort posten.
Ich habe einige Erweiterungsmethoden für die .NET Random-Klasse erstellt , einschließlich einer Implementierung der Box-Muller-Transformation. Da es sich um Erweiterungen handelt, können Sie dies tun, solange das Projekt enthalten ist (oder Sie auf die kompilierte DLL verweisen)
var r =newRandom();var x = r.NextGaussian();
Hoffe, niemand stört den schamlosen Stecker.
Beispielhistogramm der Ergebnisse (eine Demo-App zum Zeichnen ist enthalten):
Ihre Erweiterungsklasse hat ein paar Dinge, nach denen ich gesucht habe! Vielen Dank!
Thomas
1
Sie haben einen kleinen Fehler in Ihrer NextGaussian-Methode. NextDouble () Gibt eine zufällige Gleitkommazahl zurück, die größer oder gleich 0,0 und kleiner als 1,0 ist. Also solltest du u1 = 1.0 haben - NextDouble () .... anderes Protokoll (0) wird explodieren
Mitch Wheat
21
Math.NET bietet diese Funktionalität. Hier ist wie:
double mean =100;double stdDev =10;MathNet.Numerics.Distributions.Normal normalDist =newNormal(mean, stdDev);double randomGaussianValue= normalDist.Sample();
Gute Antwort! Diese Funktion ist in NuGet im MathNet.Numerics-Paket verfügbar . Immer toll, nicht selbst rollen zu müssen.
jpmc26
8
Ich habe eine Anfrage für eine solche Funktion in Microsoft Connect erstellt. Wenn Sie danach suchen, stimmen Sie dafür und erhöhen Sie die Sichtbarkeit.
Diese Funktion ist im Java SDK enthalten. Die Implementierung ist als Teil der Dokumentation verfügbar und kann problemlos in C # oder andere .NET-Sprachen portiert werden.
Wenn Sie reine Geschwindigkeit suchen, wird der Zigorat-Algorithmus allgemein als der schnellste Ansatz anerkannt.
In der Zwischenzeit finden Sie hier einen Wrapper Random, der eine effiziente Implementierung der Box Muller-Polarmethode ermöglicht:
publicsealedclassGaussianRandom{privatebool _hasDeviate;privatedouble _storedDeviate;privatereadonlyRandom _random;publicGaussianRandom(Random random =null){
_random = random ??newRandom();}/// <summary>/// Obtains normally (Gaussian) distributed random numbers, using the Box-Muller/// transformation. This transformation takes two uniformly distributed deviates/// within the unit circle, and transforms them into two independently/// distributed normal deviates./// </summary>/// <param name="mu">The mean of the distribution. Default is zero.</param>/// <param name="sigma">The standard deviation of the distribution. Default is one.</param>/// <returns></returns>publicdoubleNextGaussian(double mu =0,double sigma =1){if(sigma <=0)thrownewArgumentOutOfRangeException("sigma","Must be greater than zero.");if(_hasDeviate){
_hasDeviate =false;return _storedDeviate*sigma + mu;}double v1, v2, rSquared;do{// two random values between -1.0 and 1.0
v1 =2*_random.NextDouble()-1;
v2 =2*_random.NextDouble()-1;
rSquared = v1*v1 + v2*v2;// ensure within the unit circle}while(rSquared >=1|| rSquared ==0);// calculate polar tranformation for each deviatevar polar =Math.Sqrt(-2*Math.Log(rSquared)/rSquared);// store first deviate
_storedDeviate = v2*polar;
_hasDeviate =true;// return second deviatereturn v1*polar*sigma + mu;}}
Ich habe allerdings ein paar Werte davon. kann jemand überprüfen, was los ist?
mk7
@ mk7, eine um Null zentrierte Gaußsche Wahrscheinlichkeitsfunktion liefert genauso wahrscheinlich negative Werte wie positive Werte.
Drew Noakes
Du hast recht! Da ich eine Liste der Gewichte in einer typischen Population mit Gaußschem PDF erhalten möchte, setze ich mu auf 75 [in kg] und Sigma auf 10. Muss ich eine neue Instanz von GaussianRandom für die Generierung festlegen? jedes zufällige Gewicht?
mk7
Sie können weiterhin Beispiele aus einer Instanz zeichnen.
Aber es funktioniert nicht richtig. Versucht, es zu zeichnen, geben einheitliche zufällige Nr.
Nikhil Chilwant
4
Hier ist eine weitere schnelle und schmutzige Lösung zum Generieren von Zufallsvariablen, die normalverteilt sind . Es zeichnet einen zufälligen Punkt (x, y) und prüft, ob dieser Punkt unter der Kurve Ihrer Wahrscheinlichkeitsdichtefunktion liegt, andernfalls wiederholen.
Bonus: Sie können Zufallsvariablen für jede andere Verteilung (z. B. Exponentialverteilung oder Poissonverteilung ) generieren, indem Sie einfach die Dichtefunktion ersetzen.
staticRandom _rand =newRandom();publicstaticdoubleDraw(){while(true){// Get random values from interval [0,1]var x = _rand.NextDouble();var y = _rand.NextDouble();// Is the point (x,y) under the curve of the density function?if(y < f(x))return x;}}// Normal (or gauss) distribution functionpublicstaticdouble f(double x,doubleμ=0.5,doubleσ=0.5){return1d/Math.Sqrt(2*σ*σ*Math.PI)*Math.Exp(-((x -μ)*(x -μ))/(2*σ*σ));}
Wichtig: Wählen Sie das Intervall von y und die Parameter σ und μ so, dass die Kurve der Funktion nicht an ihren Maximal- / Minimalpunkten (z. B. bei x = Mittelwert) abgeschnitten wird. Stellen Sie sich die Intervalle von x und y als Begrenzungsrahmen vor, in den die Kurve passen muss.
Tangenial, aber dies ist tatsächlich das erste Mal, dass mir klar wird, dass Sie Unicode-Symbole für Variablen anstelle von etwas Dummem wie _sigma oder _phi verwenden können ...
Slothario
@Slothario Ich danke Entwicklern überall für die Verwendung von 'etwas Dummem': |
user2864740
2
Ich möchte die Antwort von @ yoyoyoyosef erweitern, indem ich sie noch schneller mache und eine Wrapper-Klasse schreibe. Der anfallende Overhead bedeutet möglicherweise nicht doppelt so schnell, aber ich denke, er sollte fast doppelt so schnell sein. Es ist jedoch nicht threadsicher.
Ausgehend von den Antworten von @Noakes und @ Hameer habe ich auch eine 'Gauß'sche' Klasse implementiert. Um den Speicherplatz zu vereinfachen, habe ich sie zu einem Kind der Random-Klasse gemacht, sodass Sie auch das grundlegende Next (), NextDouble () aufrufen können. usw. aus der Gaußschen Klasse, ohne dass ein zusätzliches Zufallsobjekt erstellt werden muss, um damit umzugehen. Ich habe auch die globalen Klasseneigenschaften _available und _nextgauss entfernt, da ich sie nicht als notwendig angesehen habe, da diese Klasse instanzbasiert ist. Sie sollte threadsicher sein, wenn Sie jedem Thread ein eigenes Gauß-Objekt geben. Ich habe auch alle zur Laufzeit zugewiesenen Variablen aus der Funktion verschoben und sie zu Klasseneigenschaften gemacht. Dadurch wird die Anzahl der Aufrufe des Speichermanagers verringert, da die 4 Doubles theoretisch niemals aufgehoben werden sollten, bis das Objekt zerstört ist.
publicclassGaussian:Random{privatedouble u1;privatedouble u2;privatedouble temp1;privatedouble temp2;publicGaussian(int seed):base(seed){}publicGaussian():base(){}/// <summary>/// Obtains normally (Gaussian) distrubuted random numbers, using the Box-Muller/// transformation. This transformation takes two uniformly distributed deviates/// within the unit circle, and transforms them into two independently distributed normal deviates./// </summary>/// <param name="mu">The mean of the distribution. Default is zero</param>/// <param name="sigma">The standard deviation of the distribution. Default is one.</param>/// <returns></returns>publicdoubleRandomGauss(double mu =0,double sigma =1){if(sigma <=0)thrownewArgumentOutOfRangeException("sigma","Must be greater than zero.");
u1 =base.NextDouble();
u2 =base.NextDouble();
temp1 =Math.Sqrt(-2*Math.Log(u1));
temp2 =2*Math.PI * u2;return mu + sigma*(temp1 *Math.Cos(temp2));}}
Um die Antwort von Drew Noakes zu erweitern: Wenn Sie eine bessere Leistung als Box-Muller benötigen (etwa 50-75% schneller), hat Colin Green eine Implementierung des Ziggurat-Algorithmus in C # freigegeben, die Sie hier finden:
Ziggurat verwendet eine Nachschlagetabelle, um Werte zu verarbeiten, die weit genug von der Kurve entfernt sind und die es schnell akzeptiert oder ablehnt. In etwa 2,5% der Fälle müssen weitere Berechnungen durchgeführt werden, um festzustellen, auf welcher Seite der Kurve sich eine Zahl befindet.
Sie könnten Infer.NET ausprobieren. Es ist jedoch noch nicht kommerziell lizenziert. Hier ist dort Link
Es ist ein probabilistisches Framework für .NET, das meine Microsoft-Forschung entwickelt hat. Sie haben .NET-Typen für Distributionen von Bernoulli, Beta, Gamma, Gauß, Poisson und wahrscheinlich einige weitere, die ich ausgelassen habe.
Dies ist meine einfache, von Box Muller inspirierte Implementierung. Sie können die Auflösung an Ihre Bedürfnisse anpassen. Obwohl dies für mich sehr gut funktioniert, handelt es sich um eine begrenzte Bereichsnäherung. Denken Sie also daran, dass die Schwänze geschlossen und endlich sind, aber Sie können sie sicherlich nach Bedarf erweitern.
Dies ist meine einfache, von Box Muller inspirierte Implementierung. Sie können die Auflösung an Ihre Bedürfnisse anpassen. Dies ist sehr schnell, einfach und funktioniert für meine neuronalen Netz-Apps, die eine ungefähre Gaußsche Wahrscheinlichkeitsdichtefunktion benötigen, um die Aufgabe zu erledigen. Hoffe, es hilft jemandem, Zeit und CPU-Zyklen zu sparen. Obwohl dies für mich sehr gut funktioniert, handelt es sich um eine Annäherung an eine begrenzte Reichweite. Denken Sie also daran, dass die Schwänze geschlossen und endlich sind, aber Sie können sie sicherlich nach Bedarf erweitern.
Daniel Howard
1
Hey Daniel, ich habe eine Bearbeitung vorgeschlagen, die die Beschreibung aus Ihrem Kommentar in die Antwort selbst einbezieht. Außerdem wird das '//' entfernt, das den tatsächlichen Code in Ihrer Antwort auskommentiert hat. Sie können die Bearbeitung selbst
vornehmen,
-1
Ich glaube nicht. Und ich hoffe wirklich, dass dies nicht der Fall ist, da das Framework bereits ausreichend aufgebläht ist, ohne dass eine solche spezielle Funktionalität es noch mehr ausfüllt.
Seit wann ist die Gaußsche Distribution "spezialisiert"? Es ist weitaus allgemeiner als beispielsweise AJAX oder DataTables.
TraumaPony
@TraumaPony: Versuchen Sie ernsthaft vorzuschlagen, dass mehr Entwickler die Gaußsche Distribution verwenden als AJAX regelmäßig?
David Arno
3
Möglicherweise; Was ich sage ist, dass es viel spezialisierter ist. Es gibt nur eine Verwendung - Web-Apps. Gaußsche Verteilungen haben eine unglaubliche Anzahl von nicht verwandten Verwendungen.
TraumaPony
@ DavidArno, schlagen Sie ernsthaft vor, dass weniger Funktionalität ein Framework verbessert?
Jodrell
1
@Jodrell, um ein bestimmtes Beispiel zu nennen, ich denke, die Entscheidung, MVC als separates Framework und nicht als Teil des .NET-Hauptframeworks zu definieren, war gut.
Random.NextDouble()
) in die Umkehrung der CDF JEDER Verteilung einfügen, erhalten Sie Zufallszahlen, die DIESER Verteilung folgen. Wenn Ihre Anwendung keine genau normalverteilten Variablen benötigt, ist die logistische Verteilung eine sehr enge Annäherung an die normale und verfügt über eine leicht invertierbare CDF.Random
mithilfe der Box-Muller-Transformation (in den folgenden Antworten unten erwähnt).Antworten:
Jarretts Vorschlag, eine Box-Muller-Transformation zu verwenden, ist gut für eine schnelle und schmutzige Lösung. Eine einfache Implementierung:
quelle
stdDev
Variable gesetzt werden? Ich verstehe, dass dies für bestimmte Anforderungen konfiguriert werden kann, aber gibt es irgendwelche Grenzen (dh Max / Min-Werte)?Diese Frage scheint über Google für die .NET-Gauß-Generation zu stehen, daher dachte ich, ich würde eine Antwort posten.
Ich habe einige Erweiterungsmethoden für die .NET Random-Klasse erstellt , einschließlich einer Implementierung der Box-Muller-Transformation. Da es sich um Erweiterungen handelt, können Sie dies tun, solange das Projekt enthalten ist (oder Sie auf die kompilierte DLL verweisen)
Hoffe, niemand stört den schamlosen Stecker.
Beispielhistogramm der Ergebnisse (eine Demo-App zum Zeichnen ist enthalten):
quelle
Math.NET bietet diese Funktionalität. Hier ist wie:
Dokumentation finden Sie hier: http://numerics.mathdotnet.com/api/MathNet.Numerics.Distributions/Normal.htm
quelle
Ich habe eine Anfrage für eine solche Funktion in Microsoft Connect erstellt. Wenn Sie danach suchen, stimmen Sie dafür und erhöhen Sie die Sichtbarkeit.
https://connect.microsoft.com/VisualStudio/feedback/details/634346/guassian-normal-distribution-random-numbers
Diese Funktion ist im Java SDK enthalten. Die Implementierung ist als Teil der Dokumentation verfügbar und kann problemlos in C # oder andere .NET-Sprachen portiert werden.
Wenn Sie reine Geschwindigkeit suchen, wird der Zigorat-Algorithmus allgemein als der schnellste Ansatz anerkannt.
Ich bin jedoch kein Experte in diesem Thema - ich habe dies bei der Implementierung eines Partikelfilters für meine simulierte RoboCup 3D-Roboter-Fußballbibliothek festgestellt und war überrascht, als dies nicht im Framework enthalten war.
In der Zwischenzeit finden Sie hier einen Wrapper
Random
, der eine effiziente Implementierung der Box Muller-Polarmethode ermöglicht:quelle
Math.NET Iridium behauptet auch, "ungleichmäßige Zufallsgeneratoren (normal, poisson, binomial, ...)" zu implementieren.
quelle
Hier ist eine weitere schnelle und schmutzige Lösung zum Generieren von Zufallsvariablen, die normalverteilt sind . Es zeichnet einen zufälligen Punkt (x, y) und prüft, ob dieser Punkt unter der Kurve Ihrer Wahrscheinlichkeitsdichtefunktion liegt, andernfalls wiederholen.
Bonus: Sie können Zufallsvariablen für jede andere Verteilung (z. B. Exponentialverteilung oder Poissonverteilung ) generieren, indem Sie einfach die Dichtefunktion ersetzen.
Wichtig: Wählen Sie das Intervall von y und die Parameter σ und μ so, dass die Kurve der Funktion nicht an ihren Maximal- / Minimalpunkten (z. B. bei x = Mittelwert) abgeschnitten wird. Stellen Sie sich die Intervalle von x und y als Begrenzungsrahmen vor, in den die Kurve passen muss.
quelle
Ich möchte die Antwort von @ yoyoyoyosef erweitern, indem ich sie noch schneller mache und eine Wrapper-Klasse schreibe. Der anfallende Overhead bedeutet möglicherweise nicht doppelt so schnell, aber ich denke, er sollte fast doppelt so schnell sein. Es ist jedoch nicht threadsicher.
quelle
Ausgehend von den Antworten von @Noakes und @ Hameer habe ich auch eine 'Gauß'sche' Klasse implementiert. Um den Speicherplatz zu vereinfachen, habe ich sie zu einem Kind der Random-Klasse gemacht, sodass Sie auch das grundlegende Next (), NextDouble () aufrufen können. usw. aus der Gaußschen Klasse, ohne dass ein zusätzliches Zufallsobjekt erstellt werden muss, um damit umzugehen. Ich habe auch die globalen Klasseneigenschaften _available und _nextgauss entfernt, da ich sie nicht als notwendig angesehen habe, da diese Klasse instanzbasiert ist. Sie sollte threadsicher sein, wenn Sie jedem Thread ein eigenes Gauß-Objekt geben. Ich habe auch alle zur Laufzeit zugewiesenen Variablen aus der Funktion verschoben und sie zu Klasseneigenschaften gemacht. Dadurch wird die Anzahl der Aufrufe des Speichermanagers verringert, da die 4 Doubles theoretisch niemals aufgehoben werden sollten, bis das Objekt zerstört ist.
quelle
Um die Antwort von Drew Noakes zu erweitern: Wenn Sie eine bessere Leistung als Box-Muller benötigen (etwa 50-75% schneller), hat Colin Green eine Implementierung des Ziggurat-Algorithmus in C # freigegeben, die Sie hier finden:
http://heliosphan.org/zigguratalgorithm/zigguratalgorithm.html
Ziggurat verwendet eine Nachschlagetabelle, um Werte zu verarbeiten, die weit genug von der Kurve entfernt sind und die es schnell akzeptiert oder ablehnt. In etwa 2,5% der Fälle müssen weitere Berechnungen durchgeführt werden, um festzustellen, auf welcher Seite der Kurve sich eine Zahl befindet.
quelle
Sie könnten Infer.NET ausprobieren. Es ist jedoch noch nicht kommerziell lizenziert. Hier ist dort Link
Es ist ein probabilistisches Framework für .NET, das meine Microsoft-Forschung entwickelt hat. Sie haben .NET-Typen für Distributionen von Bernoulli, Beta, Gamma, Gauß, Poisson und wahrscheinlich einige weitere, die ich ausgelassen habe.
Es kann erreichen, was Sie wollen. Vielen Dank.
quelle
Dies ist meine einfache, von Box Muller inspirierte Implementierung. Sie können die Auflösung an Ihre Bedürfnisse anpassen. Obwohl dies für mich sehr gut funktioniert, handelt es sich um eine begrenzte Bereichsnäherung. Denken Sie also daran, dass die Schwänze geschlossen und endlich sind, aber Sie können sie sicherlich nach Bedarf erweitern.
quelle
Ich glaube nicht. Und ich hoffe wirklich, dass dies nicht der Fall ist, da das Framework bereits ausreichend aufgebläht ist, ohne dass eine solche spezielle Funktionalität es noch mehr ausfüllt.
Unter http://www.extremeoptimization.com/Statistics/UsersGuide/ContinuousDistributions/NormalDistribution.aspx und http://www.vbforums.com/showthread.php?t=488959 finden Sie jedoch .NET-Lösungen von Drittanbietern.
quelle