2014-08-30 2 views
15

Я хочу знать, является ли функция JavaScript Math.random нормальным распространением или нет, если нет, то как я могу получить числа, которые являются нормальным распределением. Я не нашел ясного ответа в Интернете или алгоритма, как создавать случайные нормально распределенные числа, которые я понимаю. Я хочу перестроить машину Шмидта (немецкий физик), машина производит случайные числа 0 или 1, и они должны быть распределены нормально, поэтому я могу нарисовать их по кривой гауссова колокола.JavaScript Math.random Нормальное распределение (кривая гауссова колокола)?

, например

случайная функция получения 120 чисел (0 или 1), а средний должен быть рядом 60 раз 0 и 1.

+1

Не ответ (потому что WASN ваш вопрос: P), но это должно помочь: http://www.meredithdodge.com/2012/05/30/a-great-little-javascript-function-for-generating-random-gaussiannormalbell- curve-numbers/ – usr2564301

+2

, усредняя несколько Math.random(), уже дает вам нормальное распределение с небольшим количеством звонков, например 3. см. здесь https://jsbin.com/tetizotugu/1/edit?js,output modify первый параметр. – GameAlchemist

+6

Этот вопрос сосет. Что означает, что «машина производит случайные числа 0 или 1 и они должны быть нормально распределены» означает? Обычно распределены 0s и 1s? Почему вы включили бы «нормальное распределение» на такой вопрос, когда вы ищете равномерное распределение двух дискретных значений? –

ответ

-56

Вы можете использовать функцию Math.random() для 0 и 1 генерации последовательности с помощью этой функции

function getZeroOrOne(){ 
    return +(Math.random() > 0.5); 
} 
+4

Эта первая ссылка действительно ужасное, страшное введение в «как создать нормальное распределение». Просто ужасно и неправильно. Пожалуйста, не давайте дополнительный трафик, связав его ... – Floris

+0

Убрали эту ссылку. – kodvin

+23

НЕТ! Гауссовый! = RandomNumber * сигма + медиана. Это ПОЛНОСТЬЮ НЕПРАВИЛЬНО. (Если только «RandomNumber» не является гауссовским/нормальным для начала.) – Leopd

4

From the spec:

15.8.2.14 (случайное)

Возвращает значение числа с положительным знаком, большим или равным 0, но менее 1, выбранным случайным образом или псевдослучайным образом с аппроксиматором y равномерное распределение в этом диапазоне, используя алгоритм или стратегию, зависящую от реализации. Эта функция не принимает аргументов.

Таким образом, это равномерное распределение , не нормальное или гауссовское. Это то, что вы найдете в любом стандартном объекте случайных чисел в любой базовой среде исполнения за пределами специализированных библиотек статистики.

+8

В нем говорится о [равномерном распределении] (https://upload.wikimedia.org/wikipedia/commons/9/96/Uniform_Distribution_PDF_SVG.svg), а не [gaussian/normal distribution] (https://upload.wikimedia.org/wikipedia/commons/7/74/Normal_Distribution_PDF.svg). – Dorian

+0

@ Dorian Я знаю; это было намерением. В самом первом предложении ОП спросил, было ли это нормальное распределение, а это не так. – Pointy

8

Вы вводите в заблуждение вывод функции (которая является равномерным распределением между 0 и 1) с необходимостью генерации гауссовского распределения путем многократного рисования случайных чисел, которые являются либо 0, либо 1 - после большого количества испытаний, их сумма будет приблизительно нормально распределена.

Вы можете использовать функцию Math.random(), а затем округлить результат до целого числа: если это < 0.5, return 0; если его> = 0,5, верните 1. Теперь у вас есть равные вероятности нуля и единицы, и вы можете продолжить подход, описанный в своем вопросе.

Просто пояснить: я не думаю, что возможно иметь алгоритм, который генерирует либо 0, либо 1 в нормально распределенном виде - для нормального распределения требуется непрерывная переменная.

Если вы сделаете вышеуказанное, за 120 номеров, вы в среднем получите 60 1 и 60 0. Фактическое распределение вы получаете будет биномиальное распределение со средним значением 60 и стандартным отклонением

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

вероятность определенного числа k, когда у вас есть n образцы с вероятностью p (который мы фиксировали в 0.5)

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

при р = 0,5, вы в конечном итоге только с биномиальных коэффициентов - которые приближаются к нормальному распределению при п> 30, обычно.

-3
//This is what I use for a Normal-ish distribution random function. 
function normal_random(){ 
    var pos = [ Math.random(), Math.random() ]; 
    while (Math.sin(pos[0] * Math.PI) > pos[1]){ 
    pos = [ Math.random(), Math.random() ]; 
    } 
    return pos[0]; 
}; 

Эта функция возвращает значение между 0 и 1. Значения около 0.5 возвращаются наиболее часто.

+1

Я отнюдь не математический гений, но моя реализация вашего алгоритма ([JSFiddle] (http://jsfiddle.net/dje3z093/1/)) возвращает абсолютно противоположное. 0,5 возвращаются наименее часто. Чтобы избежать путаницы, я думаю, вы также должны прямо указать, что это не логарифм для вычисления случайной точки в нормальном распределении, а случайная точка на окружности круга. – Pascalculator

+0

Гауссово распределение сосредоточено в нуле и неограничено. Звучит ли это как ваш алгоритм? –

+0

необходимо изменить знак с> pos [1] на

1

Я нашел эту библиотеку, которая включает в себя множество полезных функций Random. Вы можете либо установить его с помощью simjs из npm, либо просто взять файл random-node - *. Js напрямую для того, что вам нужно.

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

9

Функция, которая использует центральную предельную теорему.

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

Javascript Math.random() функция возвращает псевдослучайные переменными, которые равномерно распределены между 0 и 1. Для того, чтобы получить распределение Гаусса я использую это:

// 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()); 
} 

Я думаю, что я получил это от Кнута ,

+2

Это полярный метод Марсалья. (Https://en.wikipedia.org/wiki/Marsaglia_polar_method) – Rafi

+2

Можете ли вы объяснить аргументы за последними 3 строками возвращаемой функции? Почему «retval» должен быть положительным? Что, если среднее значение было, например, 0? Тогда я ожидаю как положительные, так и отрицательные образцы. –

+0

@ChrisK: Я думаю, что нет никаких оснований, и это неправильно. – Eric

45

Поскольку это первый результат Google для «js gaussian random» в моем опыте, я чувствую обязанность дать реальный ответ на этот запрос.

Box-Muller transform преобразует два независимых равномерных вариатора на (0, 1) в два стандартных гауссовских вариатора (среднее значение 0, дисперсия 1). Это, вероятно, не очень эффективно из-за вызовов и cos, но этот метод превосходит подход центральной предельной теоремы (суммируя N равномерных вариаций), поскольку он не ограничивает вывод ограниченным диапазоном (-N/2, N/2). Это также очень просто:

// 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); 
} 
+0

На 1000 образцов диапазон '[-3.10, 3.24]' https://gist.github.com/Dorian/919f9ad749f28e5b57e655919d7eebb9 – Dorian

+0

@Dorian Не совсем неожиданно , учитывая, что вероятность того, что нормальная переменная окажется вне этого диапазона, составляет около одного в 1000: '$ python3'; '>>> import scipy.stats как статистика'; '>>> 1 - (stats.norm.cdf (3.24) - stats.norm.cdf (-3.10))'; '0.0015652517111527375' –

+0

@Dorian: Спасибо, в итоге я использовал приблизительную гауссовую функцию, имеющую диапазон' [0, 1] 'по мере необходимости в моей программе: http://stackoverflow.com/a/39187274/407213. – Dorian

17

Я хотел бы иметь приблизительно гауссовских случайных чисел от 0 до 1, и после того, как many tests я нашел, что это самое лучшее:

function gaussianRand() { 
    var rand = 0; 

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

    return rand/6; 
} 

И в качестве бонуса :

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

Это на самом деле простое решение, которое работает очень хорошо. Увеличение коэффициента (6) ужесточает распределение. – tadman

+0

Стоит сказать, что это реализация (Центральная предельная теорема) [https://en.wikipedia.org/wiki/Central_limit_theorem], являющаяся «6» размером выборки. Он дает привилегии центральным числам и забывает количество хвостов по сравнению с кривой Гаусса. Вот моя реализация: http://plnkr.co/edit/jaky1FHCGpt81vs5Lohz?p=preview; –

2

Для тех, кто заинтересован в генерации значений нормального распределения, я бы рекомендовал c hecking это реализация алгоритма Ziggurat в JavaScript: https://www.npmjs.com/package/node-ziggurat

Код найден в странице автора является:

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(); 
} 

Создать Ziggurat.js файл, а затем:

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

Для меня он работает просто отлично, и, как я читал в Википедии, это более эффективный алгоритм, чем Box-Muller.

enter link description here

+0

, может быть, лучше добавить соответствующий код для этого, чтобы быть ответ –

+0

@RazvanDumitru Определенно, спасибо за указание, что из –

1

Это мое решение проблемы, используя Marsaglia polar method. Диапазон зависит от параметров, которые вы даете, без параметров, которые он почти никогда не генерирует ничего за пределами диапазона.

Поскольку он генерирует два нормально распределенных числа на итерацию, я объявил переменную под окном.temp.spareNormal, чтобы захватить запасной, если он есть. Не может быть лучшим местом для него, но эй.

Вам, вероятно, придется округлить результат, чтобы получить то, что вы хотите.

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; 
} 
+0

я бы упростить реализацию и потерявшие хитроумный глобальные, так: 'функция getGaussianRandom (среднее, standardDeviation) { return() => { let q, u, v, p; 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); return mean + standardDeviation * u * p; }; } ' – alecmce

+0

Комментарии теряют символы новой строки :( – alecmce

-1
let iset = 0; 
let gset; 

function randn() { 

    let v1, v2, fac, rsq; 

    if (iset == 0) { 
    do { 
    v1 = 2.0*Math.random() - 1.0; 
    v2 = 2.0*Math.random() - 1.0; 
    rsq = v1*v1+v2*v2; 
    } while ((rsq >= 1.0) || (rsq == 0)); 
    fac = Math.sqrt(-2.0*Math.log(rsq)/rsq); 
    gset = v1*fac; 
    iset = 1; 
    return v2*fac; 
} else { 
    iset = 0; 
    return gset; 
} 

}