Publishable Stuff

Rasmus Bååth's Blog


bayes.js: A Small Library for Doing MCMC in the Browser

2015-12-31

Bayesian data analysis is cool, Markov chain Monte Carlo is the cool technique that makes Bayesian data analysis possible, and wouldn’t it be coolness if you could do all of this in the browser? That was what I thought, at least, and I’ve now made bayes.js: A small JavaScript library that implements an adaptive MCMC sampler and a couple of probability distributions, and that makes it relatively easy to implement simple Bayesian models in JavaScript.

Here is a motivating example: Say that you have the heights of the last ten American presidents…

// The heights of the last ten American presidents in cm, from Kennedy to Obama 
var heights = [183, 192, 182, 183, 177, 185, 188, 188, 182, 185];

… and that you would like to fit a Bayesian model assuming a Normal distribution to this data. Well, you can do that right now by clicking “Start sampling” below! This will run an MCMC sampler in your browser implemented in JavaScript.

If this doesn’t seem to work in your browser, for some reason, then try this version of the demo.

Here is the model you just sampled from…

$$\mu \sim \text{Normal}(0, 1000) \\ \sigma \sim \text{Uniform}(0, 1000) \\ \text{heights}_i \sim \text{Normal}(\mu, \sigma) ~~~ \text{for} ~ i ~ \text{in} 1..n $$

… and this is how it is implemented in JavaScript:

/* The code below assumes that you have loaded the two modules of bayes.js:
 * - mcmc.js which implements the sampler and creates the global 
 *   object mcmc.
 * - distributions.js which implements a number of log density functions
 *   for common probability distributions and that creates the global object
 *   ld (as in log density).
 */

// The data
var heights = [183, 192, 182, 183, 177, 185, 188, 188, 182, 185];

// Parameter definitions
var params = {
  mu: {type: "real"},
  sigma: {type: "real", lower: 0}};

// Model definition
var log_post = function(state, heights) {
  var log_post = 0;
  // Priors (here sloppy and vague...)
  log_post += ld.norm(state.mu, 0, 1000);
  log_post += ld.unif(state.sigma, 0, 1000);
  // Likelihood
  for(var i = 0; i < heights.length; i++) {
    log_post += ld.norm(heights[i], state.mu, state.sigma);
  }
  return log_post;
};

// Initializing the sampler, burning some draws to the MCMC gods,
// and generating a sample of size 1000.
var sampler =  new mcmc.AmwgSampler(params, log_post, heights);
sampler.burn(1000);
var samples = sampler.sample(1000);

I’ve implemented a JavaScript MCMC procedure for fitting a Bayesian model before, but that was just for a specific model (I also implemented a MCMC procedure in BASIC, but don’t ask me why…). The idea with bayes.js is to make it easier for me (and maybe for you) to make demos of Bayesian procedures that are easy to put online. If you would like to know more about bayes.js just head over to it’s GitHub page where you will find the code and a README file full of details. You can also check out a couple of interactive demos that I’ve made:

These demos rely on the plotly library and I haven’t tested them extensively on different platforms/browsers. You should be able to change the data and model definition on the fly (but if you change some stuff, like adding multidimensional variables, the plotting might stop working).

What’s included in bayes.js?

The two major files in bayes.js are:

In addition to this the whole thing is wrapped in an Rstudio project as I’ve use R and JAGS to write some tests.

FAQ

References

Roberts, G. O., & Rosenthal, J. S. (2009). Examples of adaptive MCMC. Journal of Computational and Graphical Statistics, 18(2), 349-367. pdf

Posted by Rasmus Bååth | 2015-12-31 | Tags: Bayesian, R, Statistics, JavaScript