Add weight to randomization

I am struggling to find any resources to help with this question:

Let's say I want to generate a random number between 1 and 5, but wish the randomization is weighted at the lower end (for example, when generating a random number of children that a pair may have, which is likely to be 1-5). Where to begin? Will it involve creating a complex function to map this curve, or is there a method available to do this?

For very simple sets, I can create an array, so in the example above 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 does not require flexibility and assumes that the dataset is created manually in a script.

+3


source to share


4 answers


The “probability of having children” has a Gaussian distribution, which is the “continuous limit” of the binomial distribution. How about using binomial spread ?

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 in a function and make the parameter "5".



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, 13

Origins (histogram): 38, 28, 21, 12, 1

+5


source


Ok, as long as you are working with integers where N is the maximum child value and N is not that big, you will need O (n) space and time

I will answer the assumption that you are only using integers going from 0

to N

, see the USING section of my answer for why you don't need to specify them manually 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];

      

Description

Using the indices as integers, we have:



  • 0 with weight 0 (it will never appear)
  • 1 with weight 4
  • 2 with weight 3
  • 3 with weight 1
  • 4 with weight 1
  • 5 with weight 1

Using

How difficult it is to think in terms of a range, or if you don't want to specify all the values ​​before N

manually, you can use an object and convert it to an array by specifying a key length

equal N + 1

, like this

var N = 130, 
    weights = Array.apply(null, {
        12: 1,
        53: 3,
        130: 10,
        length: N + 1
    });

      

+3


source


You can use the idea of ​​assigning arbitrary weights to each possible result without having to create an array of that size. This is enough to assign an arbitrary weight to each possible choice, and then convert the random number to the corresponding result. The possible outcomes of a random throw do not have to be a consecutive whole 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 to be illustrative and not as the best way to write this code.

Look at the action .

You can generalize this even further so that you don't even have to enter data that explicitly points to every possible outcome, but the same principle will still apply.

+1


source


since the number Math.random()

is between 0 and 1, all you have to do is create an array with the probability 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

- a random number, so if r > pxi && r<=pxf

, it will return the answer x

.

so if I'm clear enough you can see that the ability this method returns 1 is 40%, 2 is 20%, 3 is 20%, 4 is 10% and 5 is 10%, you can easily change the probability of anwer. by changing the pxi-pxf range

0


source







All Articles