7: Conditionals, Iterations, and Probabilities
- Page ID
- 47982
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\dsum}{\displaystyle\sum\limits} \)
\( \newcommand{\dint}{\displaystyle\int\limits} \)
\( \newcommand{\dlim}{\displaystyle\lim\limits} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\(\newcommand{\longvect}{\overrightarrow}\)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\ket}[1]{\left| #1 \right>}\)
\(\newcommand{\bra}[1]{\left< #1 \right|}\)
\(\newcommand{\braket}[2]{\left< #1 \vphantom{#2} \right| \left. #2 \vphantom{#1} \right>}\)
\(\newcommand{\braopket}[3]{\left< #1 \vphantom{#2}\vphantom{#3} \right| #2 \vphantom{#1}\vphantom{#3} \left| #3 \vphantom{#1}\vphantom{#2} \right>}\)
\(\newcommand{\qmvec}[1]{\mathbf{\vec{#1}}}\)
\(\newcommand{\op}[1]{\hat{\mathbf{#1}}}\)
\(\newcommand{\expect}[1]{\langle #1 \rangle}\)
\(\newcommand{\dfn}[1]{\emph{\textbf{#1}}}\)
In this chapter we learn the foundational concepts of statistics: randomness, probability, and simulation. Randomness and probability both work with the idea of an unknown outcome, such as when we flip a coin, we don't know if it will land heads side up or tails side up.
In order to work with unknown outcomes and observe their patterns, we first need to learn two new programming techniques that can (1) check what the outcome is and (2) repeat the experiment that produces the outcome. These techniques are called conditional statements and iterations.
Comparison Expressions
Comparison expressions, also known as relational expressions in programming, are used to compare two values. For example, "5 is greater than 3" is a comparison of two values.
We were introduced to comparison expressions in Chapter 3. Data Types, where we compare numbers and strings.
Python uses the same or similar symbols for comparison as with math:
<: less than<=: less than or equal to>: greater than>=: greater than or equal to==: equal to!=: not equal to
The two values on the left and right of the comparison symbol (or operator) can be two numbers or two strings.
The result of the comparison is one of two values: True or False
True
False
Comparing Sequences
When the value to be compared is an array or a column of a DataFrame, the comparison operator applies to the entire array or column. The result will be an array of True and False values.
| flavor | price | |
|---|---|---|
| 0 | chocolate | 1.50 |
| 1 | strawberry | 1.25 |
| 2 | vanilla | 1.00 |
We check for any price that's above $1.25.
0 True
1 False
2 False
Name: price, dtype: bool
Note that the result is an array of the comparison result of each price and 1.25.
If we want to know how many ice cream flavors cost more than $1, we use the Numpy count_nonzero function with the resulting array.
Number of ice cream flavors above $1: 2
The count_nonzero will return the count of all True values. This is because internally, a Python True value is 1, and False is 0.
If we want to select the rows of the DataFrame where the cost is more than $1, we use the comparison statement with the DataFrame to select the rows where the condition is True.
selected_rows = a_DataFrame[comparison]
The selected_rows will be the rows where the comparison results in True.
| flavor | price | |
|---|---|---|
| 0 | chocolate | 1.50 |
| 1 | strawberry | 1.25 |
Conditional Statements
As we see above, a comparison is a condition. num > 0 is a comparison that describes the condition where num is a positive number.
A conditional statement is used to ask the computer to do a specific task if a certain condition is true. If the condition is not true, then the computer will not do the task.
A basic conditional statement starts with the keyword if:
if condition:
do a task
This is why the conditional statement is often also called the if statement.
In the following Code cell:
- the
conditionis whethernumis greater than 5 - if the condition is true, then the printing (the task) will take place
- if the condition is false, nothing is printed.
num is greater than 5
Can you change the value of num so that no printing will take place?
Sometimes we want to perform task 1 if the condition is true, and perform task 2 if the condition is false.
In this case, we use the longer format of the if statement:
if condition:
do task 1
else:
do task 2
Here we add the keyword else, followed by the task that needs to be done if the condition is false.
Can you predict what will be printed in the code below?
num is greater than 5
Can you change the value of num so the opposite will be printed?
In the above two cases, the condition can be one of two outcomes: True or False. But sometimes there can be more than two outcomes. An example would be a letter grade that a student receives, it can be one value out of 5 outcomes: A, B, C, D, or F.
In this case, we use the general format of the if statement, which is the longest format:
if condition 1:
do task 1
elif condition 2:
do task 2
elif condition 3:
do task 3
...
elif condition N:
do task N
else:
do task N+1
Here we see a new keyword elif, which describes one of the conditions for one of the outcomes.
To see how the if elif else statement works, we use the example of a letter grade for a student with a score of 78.
C
done
In the above example with the score of 78, the following steps will run:
- the score is compared with 90
- since the result is False, the score is compared with 80, the next condition
- since the result is False, the score is compared with 70, the next condition
- since the result is True, C is printed
- the rest of the comparisons are skipped
- the final "done" is printed
Can you predict all the steps that will be run if the score is 54?
Can you predict all the steps that will be run if the score is 95?
Iterations
By using conditional statements, we can check the outcome of an event, such as a coin toss or a letter grade from a class. Now we learn how to use iterations to repeat an event multiple times so that we can observe the general trend of the event. For example, the way we know that a coin is fair is if we toss the coin many times and see that about half the time, the coin lands on the heads side.
We will use the coin toss to show the importance of using iterations to see the trend of the outcome of an event.
First we need to generate the outcome, and we'll represent heads with 1 and tails with 0.
To simulate the random outcome of getting heads or tails, we use the random module and the randint() function of Python:
random_number = random.randint(start_num,end_num)
randint will return a random number between start_num and end_num, inclusive.
0
If we re-run the Code cell above a few times, we'll notice that sometimes the output is 1 and sometimes it's 0.
But instead of manually running the Code cell above multiple times, we can use an iteration technique to ask the computer to run the code repeatedly for us.
One technique is to use a for loop:
for i in range(number_of times):
do a task
In the for loop above, a task will be run number_of_times.
The code is called a loop because the computer will run a task for the first time, then loop back to run a task again, then loop back to run a task again... until the number_of_times is reached.
Let's break down the components of the for loop.
- The first line of code has two keywords:
forandin - The
iis a variable name,iis short for iteration. Sincea taskwill be runnumber_of times, each timea taskruns is called one iteration of the loop. - The
range()function controls thenumber_of_timesthat the computer will loop back to runa task.
Now we put the simulation of the coin flip above together with the for loop to simulate tossing the coin five times:
1
1
1
0
0
Since heads is 1 and tails is 0, we see that with the 5 simulated coin flips, we have a combination of heads and tails. Each time we run the code above, we get five different combinations of heads and tails.
Simulation
The simulation with five coin flips above shows us that each outcome is random and we can't predict what a specific outcome would be. But we can see a general pattern of the outcomes if we do many more coin flips, store all the outcomes, and then observe the pattern.
To store all the outcomes, we can use a Python list that we first discovered in Chapter 3. A list is a data type that can store many values in a sequence.
As we simulate each coin toss and get the outcome, we append or add it to the end of the list. When we've stored all data into the list, we convert the list to a Numpy array to run calculations and plot more efficiently.
[1 1 0 0 1 1 1 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 1 0 0
1 1 0 0 0 0 0 0 1 1 0 0 0 0 1 0 1 0 1 0 0 1 1 1 0 1 1 0 1 1 0 0 0 0 0 1 0
1 0 1 0 1 0 1 0 0 0 0 1 1 0 0 0 0 1 1 0 1 1 0 0 1 1]
Observing the outcome from 100 coin tosses, it looks like there are about the same number of heads (1) as tails (0). This is what we initially guessed the result would be if the coin is a fair coin.
Using the count_nonzero function, we can count the actual number of 0s and 1s to confirm our theory:
Number of heads: 41
Number of tails: 59
The above is one simulation of tossing the coin 100 times. We want to repeat this simulation 200 times and observe how many heads and tails occur in each simulation.
Step 1
Create a function to simulate a coin being tossed 100 times.
We take the code to simulate the coin toss and the code to count the heads and tails and put them together in a function named coin_toss_simulation.
Step 2
Repeat the simulation code above 200 times.
We create two more lists:
heads: to store the number of heads for each simulationtails: to store the number of tails for each simulation
Then we use a for loop to run the simulation code 200 times and store the 200 pairs of heads and tails.
Since heads and tails contain the number of heads and number of tails from 200 simulations, we expect heads and tails to contain 200 values.
Number of values in heads: 200
Number of values in tails: 200
Instead of printing the 200 values and looking at them to find a pattern, which can be cumbersome, we take advantage of data visualization and plot them in a histogram:
For both plots, we can see that the largest bins are around the 45-55 range. This means that out of the 200 simulations, many simulations have around 50 heads and 50 tails out of 100 coin tosses. There are fewer simulations where the ratio is 40/60, and the fewest simulations where the ratio is close to 35/65.
The two distributions above are called empirical distributions. They are distributions that we observe or obtain from our simulation of the coin toss. The simulation behaves exactly as we would expect for a fair coin: most simulations produce close to 50 heads and 50 tails, although the exact counts vary from one simulation to the next.
Finding Probabilities
Probability is a measure of how likely an event will happen. Probability is a value between 0 and 1, or 0% to 100%.
- When it's impossible for an event to happen, it has a probability of 0.
- When an event will happen for certain, it has a probability of 1.
An example of probability is when we toss a fair coin, the chance that a coin will land heads up is 50% or 0.5, and tails up is also 0.5.
Simulation is a powerful way to approximate the probability of the coin toss, as we've seen in the previous section. But the calculation of the probability of an event is determined through mathematics, often with the help of computers.
In this section we discuss the foundational rules for calculating probabilities by using mathematics.
Probability of an event
In math, the probability of an event is denoted as P(event).
In our coin toss simulation above there are 2 outcomes or 2 events:
- P(heads) = 0.5
- P(tails) = 0.5
Probability of an event not happening
If an event happens with probability P(event), then the probability that the event will not happen is:
P(an event does not happen) = 1 - P(event)
If the chance of rain or P(rain) is 0.4, then the chance of it not raining is 0.6.
Probability of an outcome when multiple outcomes are equally likely
When an event has multiple, equally likely outcomes, such as rolling a six-sided die, then the chance of getting a particular side is:
P(a particular side) = 1 / total number of sides
This means when tossing a coin, which has 2 outcomes, the probability of getting tails is: 1/2.
It means when rolling a die, which has 6 sides, the probability of getting a 3 is: 1/6.
Probability of a subset of multiple outcomes
When an event has multiple, equally likely outcomes, such as rolling a die, the probability of getting a subset of N of the outcomes is:
P(one of N particular sides) = N * (1 / total number of sides)
This means when rolling a die:
- The chance of getting a 3 is: 1/6.
- The chance of getting a side that is a multiple of 2 (which is 2, 4, or 6) is: 1/6 + 1/6 + 1/6 = 3/6.
- The chance of getting a 1 or a 6 is: 1/6 + 1/6 = 2/6
Note that when we calculate the probability of multiple events that are ORed together (such as 1 or 6), we add together the probabilities of each event.
The combined probability of events that are ORed together is larger, which means it's more likely to happen.
Probability of multiple outcomes in a sequence
Suppose we have 3 cards: 1 red card, 1 green card, and 1 blue card. If we draw 2 cards out of the 3 cards without looking at them, then what is the probability of getting a red card first, then a green card second?
- To get a red card out of the 3 cards, the probability is: 1/3
- To get a green card out of the remaining 2 cards, the probability is: 1/2
- The combined probability of the 2 outcomes that are in sequence is 1/3 * 1/2 = 1/6
Note that when we calculate the probability of multiple events that are ANDed together (such as red and green), we multiply the probabilities of each event.
When events are ANDed together, the combined probability is smaller, which means it's less likely to happen.
Probability of at least one success
In our simulation function of 100 coin tosses above, we observe from the histogram of the number of heads that there are 35 to 65 times out of 100 that the outcome is heads.
We also know from when we simulate only one coin toss, that there's a chance that we'll have 0 heads.
How do we find the general probability of getting at least one heads with a certain number of coin tosses?
First, we hand calculate the probability for the first few coin tosses:
- For 1 coin toss
P(1 heads) = 1/2 - For 2 coin tosses
P(at least 1 heads) = 1-P(2 tails) = 1-(1/2 * 1/2) = 3/4 - For 3 coin tosses
P(at least 1 heads) = 1-P(3 tails) = 1-(1/2 * 1/2 * 1/2) = 7/8 - For 4 coin tosses
P(at least 1 heads) = 1-P(4 tails) = 1-(1/2 * 1/2 * 1/2 * 1/2) = 15/16
From the first 4 calculations, we can generalize the formula to N tosses:
P(at least 1 heads) = 1 - P(N tails) = 1-(1/2)^N
Now we can find the probability of getting at least one head for any number of coin tosses.
We also observe that as N gets larger, which means the number of coin tosses is larger, then the value \((1/2)^N\) gets smaller, which means the probability of getting at least one head approaches 1 or 100% certainty.
Summary
In this chapter we learn some new programming techniques, conditional statements and iterations. We use these techniques to work with some foundational concepts of statistics: when the outcome of an event is random, we can simulate it repeatedly to estimate the probability that the event occurs.


