Generate random number with a non-uniform distribu

2019-02-06 13:47发布

问题:

Javascript's Math.random() returns a psuedo-random number with "uniform" distribution.

I need to generate a random number in the range [0,1] that is skewed to either side. (Meaning, higher chance of getting more numbers next to 0 or next to 1)

Ideally I would like to have a parameter to set this curve.

I supposed I can do Math.random^2 to get such a result, but what more sophisticated ways are there to achieve this?

回答1:

I think you want beta distribution with alpha=beta=0.5

It is possible to transform uniform random number to beta distribution using inverse cumulative distribution.

unif = Math.random()

I am not familiar with javascript, but this should be clear:

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

PS: you can generate many such numbers and plot histogram

Edit:

For skewing towards 0, transform the beta values as -

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

For skewing towards 1, transform as -

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



回答2:

Yoy can use window.crypto.getRandomValues where available

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

var randVal = new Uint8Array(1);

window.crypto.getRandomValues(randVal);

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

On jsfiddle

(if that's what your asking for, I'm not sure)

Or maybe as this

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

also on jsfiddle



回答3:

I think you need to rethink your question. The Poisson is a counting distribution specified in terms of a rate, such as how many occurrences of something do I see on average per time period. It yields positive integers so the result can't be just in the range [0,1]. Can you please clarify what you want?

Regardless, to generate a Poisson with rate lambda one algorithm is:

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

where "rand" is the function call for a Uniform(0,1). I don't know javascript, but that should be straightforward enough for you to implement.

Responding to edited question:

There are several distributions that generate outcomes on a bounded range, but many of them aren't for the faint of heart, such as the Johnson family or the Beta distribution.

An easy one would be triangle distributions. Sqrt(rand) will give a triangle distribution bunched towards 1, while (1-Sqrt(1-rand)) will give a triangle distribution bunched towards zero.

A more general triangle with the mode (most frequent value) at m (where 0 <= m <= 1) can be generated with

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

Note that each invocation of rand is a separate Uniform random number, this won't be correct if you generate one value for rand and use it throughout.



回答4:

I just came up with a simpler way to get random numbers skewed to each side, and which doesn't have any dependencies.

This method uses two of Javascript's regular random numbers. The first is multiplied with itself (the larger the exponent, the bigger the skewing effect), and the second chooses which side of the distribution to skew to.

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

In this code the exponent is set to 2. A sample histogram from 10,000 executions with the exponent at 2 as above:

With exponent 3:

And with exponent 10: