Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a library to generate random numbers according to a beta distribution for JavaScript?

I need to generate random numbers from JavaScript within the Beta probability distribution. I've Googled but can't find any libraries that appear to support this.

Can anyone suggest where I can find a library or code snippet that will do this?

like image 296
sanity Avatar asked Mar 06 '12 19:03

sanity


People also ask

Does JavaScript have a random number generator?

Javascript creates pseudo-random numbers with the function Math. random() . This function takes no parameters and creates a random decimal number between 0 and 1. The returned value may be 0, but it will never be 1.

How do you generate a random number from a given distribution?

Perhaps the most generic way to do so is called inverse transform sampling: Generate a uniform random number in [0, 1]. Run the quantile function (also known as the inverse CDF or the PPF) on the uniform random number. The result is a random number that fits the distribution.

Which object can be used to generate random numbers in JavaScript?

Math.random() The Math.random() function returns a floating-point, pseudo-random number that's greater than or equal to 0 and less than 1, with approximately uniform distribution over that range — which you can then scale to your desired range.

Which function is used to get a random number in JavaScript?

In JavaScript, you can generate a random number with the Math. random() function.


2 Answers

The jStat library has functions to sample from a beta distribution, as well as many other distributions.

var random_num = jStat.beta.sample( alpha, beta );
like image 20
Josh de Leeuw Avatar answered Oct 04 '22 22:10

Josh de Leeuw


My translation. It's pretty much word for word, so it's probably not the most idiomatic javascript.

// javascript shim for Python's built-in 'sum'
function sum(nums) {
  var accumulator = 0;
  for (var i = 0, l = nums.length; i < l; i++)
    accumulator += nums[i];
  return accumulator;
}

// In case you were wondering, the nice functional version is slower.
// function sum_slow(nums) {
//   return nums.reduce(function(a, b) { return a + b; }, 0);
// }
// var tenmil = _.range(1e7); sum(tenmil); sum_slow(tenmil);

// like betavariate, but more like R's name
function rbeta(alpha, beta) {
  var alpha_gamma = rgamma(alpha, 1);
  return alpha_gamma / (alpha_gamma + rgamma(beta, 1));
}

// From Python source, so I guess it's PSF Licensed
var SG_MAGICCONST = 1 + Math.log(4.5);
var LOG4 = Math.log(4.0);

function rgamma(alpha, beta) {
  // does not check that alpha > 0 && beta > 0
  if (alpha > 1) {
    // Uses R.C.H. Cheng, "The generation of Gamma variables with non-integral
    // shape parameters", Applied Statistics, (1977), 26, No. 1, p71-74
    var ainv = Math.sqrt(2.0 * alpha - 1.0);
    var bbb = alpha - LOG4;
    var ccc = alpha + ainv;

    while (true) {
      var u1 = Math.random();
      if (!((1e-7 < u1) && (u1 < 0.9999999))) {
        continue;
      }
      var u2 = 1.0 - Math.random();
      v = Math.log(u1/(1.0-u1))/ainv;
      x = alpha*Math.exp(v);
      var z = u1*u1*u2;
      var r = bbb+ccc*v-x;
      if (r + SG_MAGICCONST - 4.5*z >= 0.0 || r >= Math.log(z)) {
        return x * beta;
      }
    }
  }
  else if (alpha == 1.0) {
    var u = Math.random();
    while (u <= 1e-7) {
      u = Math.random();
    }
    return -Math.log(u) * beta;
  }
  else { // 0 < alpha < 1
    // Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
    while (true) {
      var u3 = Math.random();
      var b = (Math.E + alpha)/Math.E;
      var p = b*u3;
      if (p <= 1.0) {
        x = Math.pow(p, (1.0/alpha));
      }
      else {
        x = -Math.log((b-p)/alpha);
      }
      var u4 = Math.random();
      if (p > 1.0) {
        if (u4 <= Math.pow(x, (alpha - 1.0))) {
          break;
        }
      }
      else if (u4 <= Math.exp(-x)) {
        break;
      }
    }
    return x * beta;
  }
}

Partially testable with means, which are easily calculated:

function testbeta(a, b, N) {
  var sample_mean = sum(_.range(N).map(function() { return rbeta(a, b); })) / N;
  var analytic_mean = a / (a + b);
  console.log(sample_mean, "~", analytic_mean);
}
testbeta(5, 1, 100000);
like image 129
chbrown Avatar answered Oct 04 '22 21:10

chbrown