Count your probabilities using Python
Everyone familiar with probabilities knows that they can be tricky. And when solving even really simple problems an answer might be unituitive (as in famous Linda problem). The simplest way to count your probability is by using straightforward formula
P = (number of successful outcomes) / (number of all outcomes). There is one issue with this approach though: we need to know the size for the space of the events in order to calculate the result. That’s why there is a number of other helpful formulae allowing to make shortcut calculation. With a help of a computer we can easily generate vast amount of possible outcomes and verify that we have applied correct equation for the particular problem. In this article I’ll show couple of examples that will make us sure the solution is correct for some unintuitive examples.
There are 10 white beads and 6 black beads in your pocket. You pull 2 of those beads out of your pocket at random, without replacement. What is the probability that both beads are the same color?
With a help of combinatorics we can calculate number of possible arrangements of two beads from 16 total items.
C(16 2) = 16! / (2! 14!) = 120. Now we need to count the number of positive outcomes.
It’s the same formula for white
C(10 2) = 10! / (2! 8!) = 45 and for black
C(6 2) = 6! / (2! 4!) = 15. Using sum rule for independent events
45/120 + 15/120 = 60/120 = 1/2 which is the final answer.
We’ll start with generating all possible outcomes for an action. Let’s represent our beads with numbers. Each unique number represents one bead and we use even numbers for black beads and odd numbers for white beads. These helper functions will tell them apart.
Next we generate all possible outcomes (taking two beads from our initial bag) with a help of permutation function. We’ll heavily rely on itertools module later, so make sure you’ve imported required functions to follow examples below like this
from itertools import count, permutations, islice, product
This will help us quickly initialize input sequences in a functional programming manner.
black_beads = list(islice(filter(is_black, count()), 6))
Inspecting the whole list of outcomes shows us that we have exactly the half of the pairs with matching color which is the same as calculated by a formula.
successful_outcomes = list(filter(same_color_pair, outcomes))
0.5 is our
1/2 probability. You may notice that we have
240 outcomes in our space but
120 when calculating via equation. That’s because an order doesn’t matter for us, so taking
4 and then
11 is the same as taking
11 and then
4 because we consider only matching of their colors.
There are 5 black beads and 5 white beads in your pocket. You pull the beads out of your pocket one at a time, at random and without replacement. What is the probability that the third bead drawn from your pocket is the same color as the first?
In my opinion this is very unintuitive problem. After pulling first bead we have only 9 of them left in the bag. Also we have no information about second bead at all. Suppose we pulled out black bead then we still have equal probability for each of the 9 beads. Since only 4 of them are black we have
4/9 probability of matching color. Probability wouldn’t change for the white bead too as we follow the same logic.
First we define a function for comparing color of first and third bead drawn
and then follow usual procedure of generating space of possible events
beads = list(islice(count(), 10))
This gives us expected
320/720 = 4/9 resulting probability.
You flip a fair coin 10 times. What is the probability that there are exactly 8 heads in those 10 flips?
For each coin we have two possible states so there are
2x2x...x2 (ten times)
2^10 total states. We need to pick eight heads from these arrangements so we need to count combinations of 8 elements from 10 total
In our case
k=8, so calculation gives us
10! / (8! 2!) = 45. Using our base formula we can infer
45/2^10 = 45/1024 probability of having exactly 8 heads for our 10 flips.
1 represent a head and
0 represent a tail. We need to generate all possible arrangements of zeros and ones with a length of 10 and then count how many outcomes contain exactly 8 entires of heads. This simple function will do that for us
As before we output the ration between successful events and number of total events
outcomes = list(product([1, 0], repeat=10))
45/1024 is confirmed.
There are 10 blue marbles and 7 red marbles in a bag. What is the probability that three marbles drawn from the bag (without replacement) are all red?
C(17 3) = 17! / (3! 14!) = 680 possible ways to draw three marbles. There are only
C(7 3) = 7! / (3! 4!) = 35 distinct combinations for three red marbles. So our probability is
35/680 = 7/136.
We begin by defining helper function which will tell us whether all the marbles in our sample are red.
We will map blue color to black and red color to white not to introduce new functions and reuse existing ones.
blue_marbles = list(islice(filter(is_black, count()), 10))
This gives us
210/4080 probability which is the same as ours
7/136 final result.
When in doubt verify your solution with a help of a code. That will make you double think on a problem and spot any flaws in your conclusions. In the next article I will show you how similar technique to the problems where you cannot generate whole space of possible events with a help of LLN (law of large numbers) and Monte Carlo method. Leave your comments and questions below and see you soon.