webentwicklung-frage-antwort-db.com.de

JavaScript Math.random Normalverteilung (Gaußsche Glockenkurve)?

Ich möchte wissen, ob die JavaScript-Funktion Math.random verwendet eine normale (vs. gleichmäßige) Verteilung oder nicht.

Wenn nicht, wie kann ich Nummern erhalten, die eine Normalverteilung verwenden? Ich habe im Internet keine eindeutige Antwort für einen Algorithmus zur Erzeugung zufälliger normalverteilter Zahlen gefunden.

Ich möchte eine Schmidt-Maschine (deutscher Physiker) umbauen. Die Maschine erzeugt Zufallszahlen von 0 oder 1 und diese müssen normalverteilt sein, damit ich sie als Gaußsche Glockenkurve zeichnen kann.

Beispielsweise erzeugt die Zufallsfunktion 120 Zahlen (0 oder 1) und der Durchschnitt (Mittelwert) dieser summierten Werte muss nahe 60 liegen.

43
Mangooxx

Ich möchte wissen, ob die JavaScript-Funktion Math.random normal verbreitet ist oder nicht

Javascript Math.random is not eine Normalverteilung (Gaußsche Glockenkurve) . From ES 2015, 20.2.2.27 "Gibt einen Zahlenwert mit positivem Vorzeichen zurück, der größer oder gleich 0, aber kleiner als 1 ist und zufällig oder pseudozufällig mit ungefähr gleichmäßiger Verteilung über diesen Bereich unter Verwendung einer Implementierung ausgewählt wird -abhängiger Algorithmus oder Strategie. Diese Funktion benötigt keine Argumente. " Wenn also n hoch genug ist, erhalten wir eine annähernd gleichmäßige Verteilung. Alle Werte im Intervall haben die gleiche Wahrscheinlichkeit des Auftretens (gerade Linie parallel zur x-Achse, die eine Zahl zwischen 0,0 und 1,0 angibt).

wie bekomme ich normalverteilte Zahlen?

Es gibt verschiedene Möglichkeiten, eine Sammlung von Zahlen mit einer Normalverteilung zu erhalten. Wie von Maxwell Collard beantwortet, wandelt Box-Muller-Transformation die Gleichverteilung in Normalverteilung um (der Code ist in Maxwell Collard-Antwort ​​zu finden).

Eine Antwort auf eine andere Stapelüberlaufantwort auf eine Frage hat eine Antwort mit einer anderen gleichmäßigen Verteilung auf normale Verteilungsalgorithmen. Wie zum Beispiel: Ziggurat, Verhältnis der Uniformen, Umkehren der CDF Neben einer der Antworten heißt es: sagt:

Der Ziggurat-Algorithmus ist dafür ziemlich effizient, obwohl die Box-Muller-Transformation von Grund auf einfacher zu implementieren ist (und nicht verrückt langsam).

Und schlussendlich

Ich möchte eine Schmidt-Maschine (deutscher Physiker) umbauen, die Maschine erzeugt Zufallszahlen von 0 oder 1 und sie müssen normalverteilt sein, damit ich sie in Gaußscher Glockenkurve zeichnen kann.

Wenn wir nur zwei Werte (0 oder 1) haben, sieht die Gauß-Kurve wie eine gleichmäßige Verteilung mit zwei möglichen Werten aus. Deshalb ein einfaches

function randomZero_One(){
    return Math.round(Math.random());
}

würde genügen. Es würde pseudozufällig mit ungefähr gleichen Wahrscheinlichkeitswerten 0 und 1 zurückkehren.

41
kodvin

Da dies nach meiner Erfahrung das erste Google-Ergebnis für "js gaussian random" ist, fühle ich mich verpflichtet, diese Frage tatsächlich zu beantworten.

Die Box-Muller-Transformation wandelt zwei unabhängige gleichförmige Variablen auf (0, 1) in zwei Standard-Gauß-Variablen um (Mittelwert 0, Varianz 1). Dies ist wahrscheinlich aufgrund der sqrt-, log- und cos -Aufrufe nicht sehr performant, aber diese Methode ist den Ansätzen des zentralen Grenzwertsatzes überlegen (Summieren von N gleichförmigen Variablen). weil es die Ausgabe nicht auf den begrenzten Bereich (-N/2, N/2) beschränkt. Es ist auch ganz einfach:

// Standard Normal variate using Box-Muller transform.
function randn_bm() {
    var u = 0, v = 0;
    while(u === 0) u = Math.random(); //Converting [0,1) to (0,1)
    while(v === 0) v = Math.random();
    return Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );
}
97
Maxwell Collard

Normalverteilung zwischen 0 und 1

Aufbauend auf Maxwells Antwort verwendet dieser Code die Box-Muller-Transformation , um eine Normalverteilung zwischen 0 und einschließlich 1 zu erhalten. Es werden nur die Werte neu abgetastet, wenn mehr als 3,6 Standardabweichungen entfernt sind (weniger als 0,02% Chance).

function randn_bm() {
    var u = 0, v = 0;
    while(u === 0) u = Math.random(); //Converting [0,1) to (0,1)
    while(v === 0) v = Math.random();
    let num = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );
    num = num / 10.0 + 0.5; // Translate to 0 -> 1
    if (num > 1 || num < 0) return randn_bm(); // resample between 0 and 1
    return num;
}

Visualisierungen

enter image description here

n = 100

enter image description here

n = 10.000

enter image description here

n = 10.000.000

Normalverteilung mit Min, Max, Skew

Mit dieser Version können Sie einen Min-, Max- und Skew-Faktor angeben. Siehe meine Anwendungsbeispiele unten.

function randn_bm(min, max, skew) {
    var u = 0, v = 0;
    while(u === 0) u = Math.random(); //Converting [0,1) to (0,1)
    while(v === 0) v = Math.random();
    let num = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );

    num = num / 10.0 + 0.5; // Translate to 0 -> 1
    if (num > 1 || num < 0) num = randn_bm(min, max, skew); // resample between 0 and 1 if out of range
    num = Math.pow(num, skew); // Skew
    num *= max - min; // Stretch to fill range
    num += min; // offset to min
    return num;
}

enter image description here

randn_bm(-500, 1000, 1);

enter image description here

randn_bm(10, 20, 0.25);

enter image description here

randn_bm(10, 20, 3);
49
joshuakcockrell

Ich wollte ungefähr Gaußsche Zufallszahlen zwischen 0 und 1 haben, und nach vielen Tests fand ich das am besten:

function gaussianRand() {
  var Rand = 0;

  for (var i = 0; i < 6; i += 1) {
    Rand += Math.random();
  }

  return Rand / 6;
}

Und als Bonus:

function gaussianRandom(start, end) {
  return Math.floor(start + gaussianRand() * (end - start + 1));
}
38
Dorian

Die Pseudozufallsfunktion Javascript Math.random () gibt Variablen zurück, die gleichmäßig zwischen 0 und 1 verteilt sind. Um eine Gaußsche Verteilung zu erhalten, verwende ich Folgendes:

// returns a gaussian random function with the given mean and stdev.
function gaussian(mean, stdev) {
    var y2;
    var use_last = false;
    return function() {
        var y1;
        if(use_last) {
           y1 = y2;
           use_last = false;
        }
        else {
            var x1, x2, w;
            do {
                 x1 = 2.0 * Math.random() - 1.0;
                 x2 = 2.0 * Math.random() - 1.0;
                 w  = x1 * x1 + x2 * x2;               
            } while( w >= 1.0);
            w = Math.sqrt((-2.0 * Math.log(w))/w);
            y1 = x1 * w;
            y2 = x2 * w;
            use_last = true;
       }

       var retval = mean + stdev * y1;
       if(retval > 0) 
           return retval;
       return -retval;
   }
}

// make a standard gaussian variable.     
var standard = gaussian(100, 15);

// make a bunch of standard variates
for(i=0; i<2000; i++) {
    console.log(standard());
}

Ich glaube, ich habe das von Knuth bekommen.

Funktion, die den zentralen Grenzwertsatz verwendet.

function normal(mu, sigma, nsamples){
    if(!nsamples) nsamples = 6
    if(!sigma) sigma = 1
    if(!mu) mu=0

    var run_total = 0
    for(var i=0 ; i<nsamples ; i++){
       run_total += Math.random()
    }

    return sigma*(run_total - nsamples/2)/(nsamples/2) + mu
}
12
Joe

Sie verwechseln die Ausgabe der Funktion (bei der es sich um eine gleichmäßige Verteilung zwischen 0 und 1 handelt) mit der Notwendigkeit, eine Gauß-Verteilung durch wiederholtes Zeichnen von Zufallszahlen zu generieren, die entweder 0 oder 1 sind. Nach einer großen Anzahl von Versuchen ist ihre Summe gleich ungefähr normalverteilt.

Sie können die Funktion Math.random() verwenden und dann das Ergebnis auf eine Ganzzahl runden: Wenn es <0,5 ist, geben Sie 0 zurück. Wenn es> = 0,5 ist, geben Sie 1 zurück. Jetzt haben Sie gleiche Wahrscheinlichkeiten von Null und Eins und können mit dem in Ihrer Frage beschriebenen Ansatz fortfahren.

Nur zur Verdeutlichung: Ich glaube nicht, dass es möglich ist, einen Algorithmus zu haben, der normalverteilt entweder Nullen oder Einsen erzeugt - für die Normalverteilung ist eine kontinuierliche Variable erforderlich.

Wenn Sie das obige für beispielsweise 120 Zahlen tun, erhalten Sie im Durchschnitt 60 Einsen und 60 Nullen. Die tatsächliche Verteilung, die Sie erhalten, ist die Binomialverteilung mit einem Mittelwert von 60 und einer Standardabweichung von

stdev = sqrt(p(1-p)N) = 5.48

Die Wahrscheinlichkeit einer bestimmten Zahl k, wenn Sie n Stichproben mit der Wahrscheinlichkeit p haben (die wir auf 0,5 festgelegt haben), beträgt

p = n! / ((n-k)! k!) p^k (1-p)^(n-k)

Wenn p = 0,5, erhalten Sie nur die Binomialkoeffizienten - die sich typischerweise der Normalverteilung für n> 30 annähern.

9
Floris

Aus der Spezifikation:

15.8.2.14 random ()

Gibt einen Zahlenwert mit positivem Vorzeichen zurück, der größer oder gleich 0, aber kleiner als 1 ist und zufällig oder pseudozufällig mit ungefähr gleichmäßiger Verteilung über diesen Bereich ausgewählt wurde. Verwendung eines implementierungsabhängigen Algorithmus oder einer Strategie. Diese Funktion akzeptiert keine Argumente.

Es ist also eine gleichmäßige Verteilung, nicht normal oder Gauß. Das finden Sie in nahezu jeder Standard-Zufallszahlenfunktion in jeder Basissprachenlaufzeit außerhalb spezialisierter Statistikbibliotheken.

8
Pointy

Für diejenigen, die daran interessiert sind, Werte einer normalen Verteilung zu generieren, würde ich empfehlen, diese Implementierung des Ziggurat-Algorithmus in JavaScript zu überprüfen: https://www.npmjs.com/package/node-ziggurat

Der Code auf der Autorenseite lautet:

function Ziggurat(){

var jsr = 123456789;

var wn = Array(128);
var fn = Array(128);
var kn = Array(128);

function RNOR(){
  var hz = SHR3();
  var iz = hz & 127;
  return (Math.abs(hz) < kn[iz]) ? hz * wn[iz] : nfix(hz, iz);
}

this.nextGaussian = function(){
  return RNOR();
}

function nfix(hz, iz){
  var r = 3.442619855899;
  var r1 = 1.0 / r;
  var x;
  var y;
  while(true){
    x = hz * wn[iz];
    if( iz == 0 ){
      x = (-Math.log(UNI()) * r1); 
      y = -Math.log(UNI());
      while( y + y < x * x){
        x = (-Math.log(UNI()) * r1); 
        y = -Math.log(UNI());
      }
      return ( hz > 0 ) ? r+x : -r-x;
    }

    if( fn[iz] + UNI() * (fn[iz-1] - fn[iz]) < Math.exp(-0.5 * x * x) ){
      return x;
    }
    hz = SHR3();
    iz = hz & 127;

    if( Math.abs(hz) < kn[iz]){
      return (hz * wn[iz]);
    }
  }
}

function SHR3(){
  var jz = jsr;
  var jzr = jsr;
  jzr ^= (jzr << 13);
  jzr ^= (jzr >>> 17);
  jzr ^= (jzr << 5);
  jsr = jzr;
  return (jz+jzr) | 0;
}

function UNI(){
  return 0.5 * (1 + SHR3() / -Math.pow(2,31));
}

function zigset(){
  // seed generator based on current time
  jsr ^= new Date().getTime();

  var m1 = 2147483648.0;
  var dn = 3.442619855899;
  var tn = dn;
  var vn = 9.91256303526217e-3;

  var q = vn / Math.exp(-0.5 * dn * dn);
  kn[0] = Math.floor((dn/q)*m1);
  kn[1] = 0;

  wn[0] = q / m1;
  wn[127] = dn / m1;

  fn[0] = 1.0;
  fn[127] = Math.exp(-0.5 * dn * dn);

  for(var i = 126; i >= 1; i--){
    dn = Math.sqrt(-2.0 * Math.log( vn / dn + Math.exp( -0.5 * dn * dn)));
    kn[i+1] = Math.floor((dn/tn)*m1);
    tn = dn;
    fn[i] = Math.exp(-0.5 * dn * dn);
    wn[i] = dn / m1;
  }
}
zigset();
}

Erstellen Sie eine Ziggurat.js-Datei und dann:

var z = new Ziggurat();
z.nextGaussian();

Für mich funktioniert es einfach perfekt und wie ich in Wikipedia gelesen hatte, ist dies ein effizienterer Algorithmus als der Box-Müller.

Linkbeschreibung hier eingeben

4
Eduardo G.R.

Und ein einzeiliges Beispiel:

Math.sqrt(-2 * Math.log(Math.random()))*Math.cos((2*Math.PI) * Math.random())

und a Fiddle https://jsfiddle.net/rszgjqf8/

4
unsalted

Eine nicht-ausführliche Funktion zum Abtasten eines Zufallswerts aus einer Gaußschen Verteilung, die ich vor einiger Zeit geschrieben habe:

function gaussianRandom(mean, sigma) {
  let u = Math.random()*0.682;
  return ((u % 1e-8 > 5e-9 ? 1 : -1) * (Math.sqrt(-Math.log(Math.max(1e-9, u)))-0.618))*1.618 * sigma + mean;
}

Es sollte funktionieren, wenn Sie die Werte auf den gewünschten Bereich begrenzen.

1
SuperEggbert

Ich habe verschiedene Funktionen mit der richtigen Konfiguration getestet, die alle ähnlich und gut funktionieren.

http://jsfiddle.net/p3y40gf3/29/

Zentrale Grenze ist Nice, muss mit (n = 3 für 6) und 12 für 12 sein, um wie andere auszusehen. Ich habe andere auch auf (6) oder 12 oder 1/12 als Standardabweichung konfiguriert, nicht sicher warum 12.

Zentrale Grenze ist ein kleines bisschen weniger zentriert als Box/Muller und Ziggurat.

Box/Muller und Ziggurat sehen genau gleich aus

diese Variante von Joe ( https://stackoverflow.com/a/33567961/46636 ) macht die Standardabweichung richtig:

function normal(mu, sigma, nsamples){ // using central limit
    if(!nsamples) nsamples = 3
    if(!sigma) sigma = 1
    if(!mu) mu=0

    var run_total = 0
    for(var i=0 ; i<nsamples ; i++){
       run_total += Math.random()
    }

    return sigma*(run_total - nsamples/2)/(nsamples/2) + mu
}

Ziggurat ist auch schön, muss aber von Z-Score auf 0 bis 1 angepasst werden. Es sieht so aus, als ob es gute Zahlen ergibt.

Box/Muller abgeschnitten ist gut, gibt aber nur wenige wiederholte Zahlen an den abgeschnittenen Kanten, ist aber anderen sehr ähnlich. Falsche Zufallszahlen sollten verworfen und nicht abgeschnitten werden.

function randn_bm() {
    var u = 0, v = 0;
    while(u === 0) u = Math.random(); //Converting [0,1) to (0,1)
    while(v === 0) v = Math.random();
    let num = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );
    num = num / 6.0 + 0.5; // Translate to 0 -> 1 // changed here 10 to 6
    if(num>1||num<0) return randn_bm(); return num; // bad random numbers should be discared not clipped
    //return Math.max(Math.min(num, 1), 0); // cap between 0 and 1
}

Die zentrale Limitvariante heißt Bates-Verteilung und ist durchschnittlich https://en.wikipedia.org/wiki/Bates_distribution

nicht verwechselt mit Irwin Hall, das ist eine Summe https://en.wikipedia.org/wiki/Irwin%E2%80%93Hall_distribution

https://en.wikipedia.org/wiki/Normal_distribution#Generating_values_from_normal_distribution

1
Shimon Doodkin

Ich habe diese Bibliothek gefunden, die viele nützliche Zufallsfunktionen enthält. Sie können es entweder über simjs von npm aus installieren oder einfach die JS-Datei random-node - * .js direkt für das herausnehmen, was Sie benötigen.

http://www.simjs.com/random.htmlhttp://www.simjs.com/download.html

1
Mark

Dies ist meine Lösung für das Problem mit der Marsaglia Polar Methode . Der Bereich hängt von den von Ihnen angegebenen Parametern ab. Ohne Parameter wird so gut wie nie etwas außerhalb des Bereichs generiert.

Da zwei normalverteilte Zahlen pro Iteration generiert werden, habe ich unter window.temp.spareNormal eine Variable deklariert, um die Ersatzvariable zu ermitteln, falls diese vorhanden ist. Könnte nicht der beste Ort dafür sein, aber hey.

Wahrscheinlich müssten Sie das Ergebnis abrunden, um das zu erhalten, was Sie wollen.

window.temp = {
    spareNormal: undefined
};

Math.normal = function (mean, standardDeviation) {
    let q, u, v, p;

    mean = mean || 0.5;
    standardDeviation = standardDeviation || 0.125;

    if (typeof temp.spareNormal !== 'undefined') {
        v = mean + standardDeviation * temp.spareNormal;
        temp.spareNormal = undefined;

        return v;
    }

    do  {
        u = 2.0 * Math.random() - 1.0;
        v = 2.0 * Math.random() - 1.0;

        q = u * u + v * v;
    } while (q >= 1.0 || q === 0);

    p = Math.sqrt(-2.0 * Math.log(q) / q);

    temp.spareNormal = v * p;
    return mean + standardDeviation * u * p;
}
1
Sjor