Select element from array with probability proportional to its value

user2341412 picture user2341412 · May 10, 2013 · Viewed 8.6k times · Source

I have an array of doubles and I want to select a value from it with the probability of each value being selected being inversely proportional to its value. For example:

arr[0] = 100
arr[1] = 200

In this example, element 0 would have a 66% of being selected and element 1 a 33% chance. I am having difficulty coding this. What I have done so far is to calculate the total value of the array (the example would be 300), then I've played around with inversing the numbers before calculating them as a percentage of the total. I can't get anything to work. In the end I desire:

new randomNumber
for(int y=0; y < probabilities.length; y++){
     if(randomNumber < probabilities[y]){
          Select probabilities[y]
     }
}

Or something to that affect. Any help? Coding is in Java but I can adapt any pseudocode.

Answer

Raymond Hettinger picture Raymond Hettinger · May 10, 2013

The usual technique is to transform the array into an array of cumulative sums:

 [10 60 5 25]  --> [10 70 75 100]

Pick a random number in the range from zero up to the cumulative total (in the example: 0 <= x < 100). Then, use bisection on the cumulative array to locate the index into the original array:

Random variable x      Index in the Cumulative Array      Value in Original Array
-----------------      -----------------------------      ----------------------
 0 <= x < 10                      0                            10
10 <= x < 70                      1                            60
70 <= x < 75                      2                             5
75 <= x < 100                     3                            25 

For example, if the random variable x is 4, bisecting the cumulative array gives a position index of 0 which corresponds to 10 in the original array.

And, if the random variable x is 72, bisecting the cumulative array gives a position index of 2 which corresponds to 5 in the original array.

For an inverse proportion, the technique is exactly the same except you perform an initial transformation of the array into its reciprocals and then build the cumulative sum array:

[10 60 5 25]  -->  [1/10  1/60  1/5  1/25]  -->  [1/10  7/60  19/60  107/300]