How to create a function that generate a random number but following a specific distribution

65 Views Asked by At

I like to create data visualizations, but I often need to generate data, and i find the random normal distribution too "boring".

I would like to create a generator of random values that follows a specified distribution.

My idea is to use a graph editor such as:

https://observablehq.com/d/ac77643d0cd9422e

From this editor i have a function distribution(x) that return the y value on the graph.

And i would like to create a distributor(distribution) function that return a random value, but the value has more "chance" to be a x if the y on the graph is high.

Edit : i added a distributor function that create a sample of 100 pair of x,y, sort them by y, iterate through it with a 100 * e chance to continue... it kinda works, but it's awful. And I don't know which value of e is better to fit the curve....

distributor = (fn, e = 0.9) => {
  let find = () =>
    d3
      .range(0, 100)
      .map(() => {
        let x = Math.random();
        return { y: fn(x), x };
      })
      .sort((a, b) => b.y - a.y)
      .find((x) => Math.random() > e);
  while (true) {
    let f = find();
    if (f) {
      return f.x;
    }
  }
}

Thanks

1

There are 1 best solutions below

0
pernifloss On

Inspired by https://prosepoetrycode.potterpcs.net/2015/05/weighted-random-choices-js/ I ended up using :

distributor = (fn, nbVal = 20) => {
  let weights = d3.range(nbVal).map((d) => fn(d / nbVal));
  var totalWeight = 0;
  totalWeight += weights.reduce((acc, v) => acc + v);
  var random = Math.random() * totalWeight;
  for (var i = 0; i < nbVal; i++) {
    random -= weights[i];
    if (random < 0) {
      return i / nbVal;
    }
  }
}

cons : you can only generate a discrete amount of value