Генерация случайных чисел с неравномерным распределением

в JavaScript Math.random() возвращает псевдо-случайное число с "равномерным" распределением.

мне нужно сгенерировать случайное число в диапазоне [0,1], что перекос в любую сторону. (Это означает, что больше шансов получить больше чисел рядом с 0 или рядом с 1)

В идеале я хотел бы иметь параметр для установки этой кривой.

Я предполагал, что могу сделать Math.random^2 чтобы получить такой результат, но какие более сложные способы для этого существуют?

4 ответов


Я думаю, вы хотите бета-распределения с alpha=beta=0.5

можно преобразовать равномерное случайное число в бета-распределение, используя обратное кумулятивное распределение.

unif = Math.random()

Я не знаком с javascript, но это должно быть ясно:

beta = sin(unif*pi/2)^2

PS: вы можете генерировать много таких чисел и построить гистограмму enter image description here

Edit:

для наклона к 0, преобразить beta значения как -

beta_left = (beta < 0.5) ? 2*beta : 2*(1-beta);

enter image description here

для отклонения в сторону 1 преобразуйте как -

beta_right = (beta > 0.5) ? 2*beta-1 : 2*(1-beta)-1;

enter image description here


можно использовать окно.криптографический.getRandomValues, где имеется

<div id="result"></div>

var randVal = new Uint8Array(1);

window.crypto.getRandomValues(randVal);

document.getElementById("result").textContent = randVal[0] / 255;

On jsfiddle

(если это то, о чем вы просите, я не уверен)

или, может быть, как этот

<div id="result"></div>

function poissonRandomNumber(lambda) {
    var L = Math.exp(-lambda),
        k = 0,
        p = 1;

    do {
        k = k + 1;
        p = p * Math.random();
    } while (p > L);

    return k - 1;
}

document.getElementById("result").textContent = poissonRandomNumber(100);

на jsfiddle


Я думаю, вам нужно пересмотреть свой вопрос. Пуассон-это распределение подсчета, заданное в терминах скорости, например, сколько вхождений чего-то я вижу в среднем за период времени. Он дает положительные целые числа, поэтому результат не может быть только в диапазоне [0,1]. Не могли бы Вы уточнить, чего вы хотите?

независимо от того, для генерации Пуассона со скоростью лямбда один алгоритм:

threshold = Math.exp(-lambda)
count = 0
product = 1.0
while (product *= rand) >= threshold {
      count += 1
}
return count

где "rand" - вызов функции для равномерного(0,1). Я не знаю javascript, но это должно быть достаточно просто для вас, чтобы реализовать.

отвечая на отредактированный вопрос:

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

легким было бы распределение треугольников. Функция sqrt(Рэнд) даст распределение треугольник, образованный к 1, а (1-корень(1-Рэнд)) даст распределение треугольников сгруппировано к нулю.

более общий треугольник с режимом (наиболее частое значение) в m (где 0

if rand <= m
    return m * Sqrt(rand)
else
    return 1 - ((1 - m) * Sqrt(1 - rand))

обратите внимание, что каждый вызов rand является отдельным однородным случайным числом, это будет неправильно, если вы создадите одно значение для rand и будете использовать его повсюду.


Я просто придумал более простой способ получить случайные числа, перекошенные в каждую сторону, и у которых нет никаких зависимостей.

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

function skewedRandom() {
    const a = Math.pow(Math.random(), 2);
    if (Math.random() < 0.5) {
        return a;
    }
    return 1 - a;
}

в этом коде показатель равен 2. Пример гистограммы из 10 000 исполнений с показателем в 2 как и выше:

Histogram with exponent 2

с показателем 3:

Histogram with exponent 3

и с показателем 10: Histogram with exponent 10