🎲 Picking a Random Sample From a Non-Uniform Distribution | by Marte Løge | Towards Data Science

I bet you have come across the situation where you have to pick a random item for a set of items? This has a quite simple solution as all items have the same probability of being picked.
But what if each item has a different probability for being picked — in other words — the distribution is not uniform. How can this be solved? It is not a hard problem to solve, but you might not find yourself bumping into this problem very often in your daily programming work.
Let's have a look at an example and solve it using java, python, and javascript.
When you go fishing — what fish biting on the hook is random. Buy taking some notes you might see more occurrences of some types of fish than others — meaning that the probability of getting some types of fish are higher than others.
Today we will go fishing together at our imaginary place where you will find 3 kinds of fishes: cod, halibut, and mackerel. Based on my last 50 catches I caught 15 cod, 5 halibut, and 30 mackerel. Based on the observations, the likelihood of getting a mackerel is 60%, 30% for getting cod, and only 10% of getting a halibut on the hook.
halibut: 10% (5)cod: 30% (15)mackerel: 60% (30)
Let's make a “fishing simulator” simulating our fishing trip.
If we got the same probability of getting any kind of fish we could just run a random generator giving us a number between say 1–3 telling what kind of fish we got. Tada! Unfortunately — the world does not work that way. How can we then simulate the fishing experience using the non-uniform probability distribution for cod, halibut, and mackerel?
The solution is “aggregated probability”. If you want to win a lottery you buy yourself as many tickets as you can. Because when they call a number you are more likely to be the winner. We are gonna think in the same way picking a random number in a non-uniform distribution!
So if we have 10 tickets, the cod will get 1 ticket, the halibut will get 3 tickets and the mackerel will get 6 tickets.
halibut: 10% (5) - 10 tickets --> ticket #1cod: 30% (15) - 30 tickets --> ticket #2 - #4mackerel: 60% (30) - 60 tickets --> ticket #5 - #10
Now, to try our luck we can run a random generator giving us a number between 1 and 10 telling us what fish we got 🎉 Since the mackerel has more tickets (eg has a higher likelihood of being caught) it will have more chances of being picked.
You maybe have the same problem you want to solve so I put together some different solutions written in different languages. It is just one way of solving it and each language probably has many different neat solutions. If you have a nicer way of solving this — please share with us all in a comment 🙌
In Java, you can use a TreeMap to make it easy for you to catch a random fish. Add all fishes with the aggregated probabilities (eg giving out the “tickets”). The TreeMap has a built-in higherEntry that will pick the items aggregated probability strictly greater than the given random number.
Here, the halibut has the tickets up to 0.1, the cod has the tickets starting from 0.1 to 0.4 and the mackerel has the tickets starting from 0.4 to 1.
TreeMap<Double, Fish> fishes = new TreeMap<>();movies.put(0.1, new Movie("Halibut")); //0.1movies.put(0.4, new Movie("Cod")); //0.1 + 0.3 --> 0.4movies.put(1.0, new Movie("Mackerel")); //0.4 + 0.6 --> 1Fish catched = fishes.higherEntry(Math.random()).getValue();
In javascript, we first assign the fishes their tickets using the map function by aggregate the probability. Then we use find for finding the fish closest to the random aggregated probability.
const fishes = [  {type: "halibut", prob: 0.1},  {type: "cod", prob: 0.3},  {type: "mackerel", prob: 0.6}];const random = Math.random();let aggregated_probability = 0;const randomFish = fishes.map((fish) => {  aggregated_probability += fish.prob;  return { type: fish.type, prob: aggregated_probability };}).find((fish) => fish.prob >= random);// outputs random fish
When using a map on fishes it will give us a new array looking like this:
[{type: "halibut", prob: 0.1}, {type: "cod", prob: 0.4}, {type: "mackerel", prob: 1.0}]
The find will look for the fish having the random lottery in their lottery range. For example — if Math.random() results in the number 0.678 the mackerel are caught. If Math.random() results in 0.0923 a halibut are caught.
For python, NumPy has already solved this for us with the “random choice”. You input your elements fishes, the number of times you want to “draw”/fish (1), and the probability distribution [0.1, 0.3, 0.6]:
import numpy as npfish = ['halibut', 'cod', 'mackerel']np.random.choice(fish, 1, p=[0.1, 0.3, 0.6])# outputs random selected fish [<fish>]
Happy coding 🙌