2

I have a homework to do, that is:

Pick a random color, from yellow, blue and red, given the probability of: Yellow: 3/7 Blue: 1/7 Red: 3/7


I know that I could work this around by using something like: [yellow, yellow, yellow, blue, red, red, red] But I don't think this would be programatically good, since when I chance the probability, I would have to change the array.

So, I thought I could try something like a weight approach

let yellow_probability = 3/7
let blue_probability = 1/7
let red_probability = 3/7
const colors = ['yellow', 'blue', 'red']
function pickPosition(yellow_probability, blue_probability, red_probability){
 let yellow_weight = Math.random() * yellow_probability
 let blue_weight = Math.random() * blue_probability
 let red_weight = Math.random() * red_probability
 let weights = [yellow_weight, blue_weight, red_weight]
 let max_of_array = Math.max.apply(Math, weights);
 pickedColor = weights.indexOf(max_of_array)
 return pickedColor
}
pickedColorIndex = pickPosition(yellow_probability, blue_probability, red_probability)
pickedColor = colors[pickedColorIndex]
console.log(pickedColor)

I did a test:

let n=1000000; 
let yellow=0, blue=0, red=0; 
for (let i=0; i<n; i++) {
 pickedColorIndex = pickPosition(yellow_probability, blue_probability, red_probability)
 if (pickedColorIndex==0) yellow++
 else if (pickedColorIndex==1) blue++
 else red++;
}
console.log("yellow = " + yellow/n );
console.log("blue = " + blue/n );
console.log("red = " + red/n );

And I would expect this test to output something like:

Yellow = 0.43
Blue = 0.14
Red = 0.43

But I am getting:

Yellow = 0.48
Blue = 0.03
Red = 0.48

It is interesting to point out that the code works when the probabilities are equal (1/3, 1/3, 1/3) or something like (1/2, 1/2, 0)

Can anyone point out what I am doing wrong?

asked May 9, 2019 at 13:57
2

2 Answers 2

4

Instead of a single random value, you create as many as different items you have and later take the one with the max value.

This promotes values/items with a higher factor/probability.

Instead of this approach, you could take a single random value and take all probabilities into an array and check in which interval the random value is. Take this item.


EDIT: The code

function getRandomIndex(probabilities) {
 var random = Math.random(),
 i;
 
 for (i = 0; i < probabilities.length; i++) {
 if (random < probabilities[i]) return i;
 random -= probabilities[i];
 }
 return probabilites.length - 1;
}
var probabilities = [3 / 7, 1 / 7, 3 / 7],
 j = 1e6,
 count = [0, 0, 0];
while (j--) count[getRandomIndex(probabilities)]++;
console.log(count);

answered May 9, 2019 at 14:03
Sign up to request clarification or add additional context in comments.

4 Comments

why not? :P I'm pretty sure no one will complain about that
But, for a single random value, wouldn't I face some problems with equals probabilities? e.g: Yellow and Red have 3/7 probability, so, if I checked the random value on them, it would conflict, wouldn't it?
If you could add some code, it would be helpful to understand your method. Anyway, I will try to implement your method as I understood, by myself.
Not yet, I didn't have access to a computer yet
1

This is similar to the approach mentioned in the duplicate. You create an array with ratios same as the probabilities. (Here I'm using 2 decimal places and adding ~100 items to the array. You could add multiply by a bigger number and have .toFixed(3) for better accuracy)

function getRandomWithProbability(array) {
 const filled = array.flatMap(([color, prob]) => {
 const length = prob.toFixed(2) * 100;
 return Array.from({ length }).fill(color)
 });
 const random = Math.floor(Math.random() * filled.length);
 return filled[random]
}
const arr = [["yellow", 3/7], ["blue", 1/7], ["red", 3/7]]
console.log(getRandomWithProbability(arr))

answered May 9, 2019 at 15:51

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.