Reputation: 1443
I'm struggling to find any resources that help with this question:
Say I want to generate a random number between 1 and 5, but wish the randomisation to be weighted toward the bottom end (like if generating a random number of children a couple might have, which is more likely to be 1 than 5). Where should I start? Would this involve creating a complex function to map that curve or is there a method available to help with this?
For very simple sets I suppose I could create an array, so for the above example I could do, for example:
var children = [1,1,1,1,2,2,2,3,4,5];
return children[Math.floor(Math.random() * children.length)];
But this lacks flexibility and assumes the data set is being created manually within the script.
Upvotes: 3
Views: 182
Reputation: 2549
The "children birth probability" has Gaussian distribution, which is a "continuous limit" of binomial distribution. What about using binomial distribution?
var val = Math.random()*5 + Math.random()*5;
// "val" will be between 0 and 10, but values around 5 are more probable
return 1 + Math.floor(Math.abs(val-5));
Just put it into function and make "5" a parameter.
Small test (http://jsfiddle.net/yt6zvs8n/):
100 output values: 1, 1, 2, 3, 2, 4, 2, 2, 2, 3, 3, 1, 2, 1, 4, 1, 2, 3, 2, 1, 4, 4, 2, 1, 4, 3, 2, 2, 1, 3, 2, 4, 1, 3, 2, 4, 2, 2, 1, 2, 1, 1, 1, 4, 1, 4, 1, 3, 1, 2, 1, 2, 1, 2, 2, 3, 2, 1, 3, 1, 2, 1, 3, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 3, 4, 1, 3, 1, 2, 5, 1, 3, 1, 3, 1, 3, 1, 4, 1, 3, 1, 3, 2, 2, 3, 1, 3, 4, 1, 3
Occurences (histogram): 38, 28, 21, 12, 1
Upvotes: 5
Reputation: 6720
since the number Math.random()
is between 0 and 1, all you have to do is create an array with the probabity that the answer is 1,2,3,4 or 5. for example
var px = [
{ answer: 1, pxi: 0.0, pxf:0.40 },
{ answer: 2, pxi: 0.40, pxf:0.60 },
{ answer: 3, pxi: 0.60, pxf:0.80 },
{ answer: 4, pxi: 0.80, pxf:0.90 },
{ answer: 5, pxi: 0.90, pxf:1 }
]
lets say r
is a random number, so if r > pxi && r<=pxf
it will return an x
answer.
so if i am clear enough you can see that the propability that this method returs 1 is 40%, 2 is 20%, 3 is 20%, 4 is 10% and 5 10%, you can easly change the probability of the anwer by changing the range pxi-pxf
Upvotes: 0
Reputation: 10849
Well as long as you work with integers, where N is the max child value and N is not so big you will need O(n) space and time
I'll answer assuming that you only use integers going from 0
to N
, see in USAGE section of my answer why you don't need to specify them by hand when their weight is 0.
var weights = [0,4,3,1,1,1];
var number = weights.reduce(function (previous, current, index) {
var value = Math.random() * (current|0);
if (value > previous[0]) {
return [value, index];
}
return previous;
}, [Math.random() * (weights[0]|0), 0])[0];
Using indices as integers, we have:
As it is not very easy to think in term of range or if you don't want to specify all values until N
manually, you can use an object and convert it to an array by specifying a key length
equal to N + 1
, like this
var N = 130,
weights = Array.apply(null, {
12: 1,
53: 3,
130: 10,
length: N + 1
});
Upvotes: 3
Reputation: 437386
You can use the idea of assigning arbitrary weights to each possible outcome without having to create an array as large as that. It's enough to assign an arbitrary weight to each possible choice, then convert a random number to the appropriate result. The possible results of the random roll need not even be a consecutive integer range.
For example:
var weights = { 1: 4, 2: 3, 3: 1, 4: 1, 5: 1 }
// pre-processing; modifies weights!
var runningTotal = 0;
for (var number in weights) {
runningTotal += weights[number];
weights[number] = runningTotal;
}
// generation
var seed = Math.floor(Math.random() * runningTotal);
// conversion of seed to result based on weights
for (var number in weights) {
if (seed < weights[number]) {
console.log("result: " + number);
break;
}
}
Note that the above is meant as an illustrative example, not as the best way to write this code.
It's possible to generalize this even further so that you don't even have to provide input that explicitly specifies every possible result, but the same principle will still apply.
Upvotes: 1