4.1 Making Decisions with Conditional Statements

Questions

  • How can my programs do different things based on data values?

In our last lesson, we discovered something suspicious was going on in our exhibit-visit data by drawing some plots. How can we use Python to automatically recognize the different features we saw, and take a different action for each? In this lesson, we’ll learn how to write code that runs only when certain conditions are true.

Conditionals

We can ask Python to take different actions, depending on a condition, with an if statement:

num = 37
if num > 100:
    print('greater')
else:
    print('not greater')
print('done')
not greater
done

The second line of this code uses the keyword if to tell Python that we want to make a choice. If the test that follows the if statement is true, the body of the if (i.e., the set of lines indented underneath it) is executed, and “greater” is printed. If the test is false, the body of the else is executed instead, and “not greater” is printed. Only one or the other is ever executed before continuing on with program execution to print “done”:

A flowchart diagram of the if-else construct that tests if variable num is greater than 100

Conditional statements don’t have to include an else. If there isn’t one, Python simply does nothing if the test is false:

num = 53
print('before conditional...')
if num > 100:
    print(num, 'is greater than 100')
print('...after conditional')
before conditional...
...after conditional

We can also chain several tests together using elif, which is short for “else if”. The following Python code uses elif to print the sign of a number.

num = -3

if num > 0:
    print(num, 'is positive')
elif num == 0:
    print(num, 'is zero')
else:
    print(num, 'is negative')
-3 is negative

Note that to test for equality we use a double equals sign == rather than a single equals sign = which is used to assign values.

Comparing in Python

Along with the > and == operators we have already used for comparing values in our conditionals, there are a few more options to know about:

  • >: greater than
  • <: less than
  • ==: equal to
  • !=: does not equal
  • >=: greater than or equal to
  • <=: less than or equal to

We can also combine tests using and and or. and is only true if both parts are true:

if (1 > 0) and (-1 >= 0):
    print('both parts are true')
else:
    print('at least one part is false')
at least one part is false

while or is true if at least one part is true:

if (1 < 0) or (1 >= 0):
    print('at least one test is true')
at least one test is true

True and False

True and False are special words in Python called booleans, which represent truth values. A statement such as 1 < 0 returns the value False, while -1 < 0 returns the value True.


Looking at our data

Let’s return to our dataset of museum visits. We’re going to focus on three files:

exhibit-visits_city-7_varied-peak.csv
exhibit-visits_city-8_varied-peak.csv
exhibit-visits_city-9_varied-peak.csv

Each file is for a different city, and contains a table with

  • 8 museums (rows)
  • 40 days (columns)

Let us load the data for the for city 7.

import numpy

data = numpy.loadtxt(fname="exhibit-visits_city-7_varied-peak.csv", delimiter=",")
print("The shape of our data is", data.shape)
The shape of our data is (8, 40)

In these cities, the museums launched their mid-exhibit advertising campaigns on different days, and the maximum number of daily visitors occurred after they launched these campaigns.

Say we want to find out whether the maximum number of visits occurred before or after the end of week 3. This is day 20 if we begin counting at 1, or day 19 if we begin counting at 0 (like Python).

daily_total = numpy.sum(data, axis=0)
end_week_3 = 19

if numpy.argmax(daily_total) > end_week_3:
    print("The max number of visitors occured after week 3")
else:
    print("The max number of visitors occured in or before week 3")
The max number of visitors occured after week 3

Now let’s see whether city 7 and city 8 were the most busy on the same day.

data_city7 = numpy.loadtxt(fname="exhibit-visits_city-7_varied-peak.csv", delimiter=",")
data_city8 = numpy.loadtxt(fname="exhibit-visits_city-8_varied-peak.csv", delimiter=",")

daily_total_city7 = numpy.sum(data_city7, axis=0)
daily_total_city8 = numpy.sum(data_city8, axis=0)

if numpy.argmax(daily_total_city7) == numpy.argmax(daily_total_city8):
    print("Cities 7 and 8 were the most busy on the same day")
else:
    print("Cities 7 and 8 were the most busy on different days")

Now let’s try something more complicated. Let’s load the data for cities 7-9 and for each city, display which week contained their most-busy day.

One way to do this is to make a dictionary that defines which days are in which weeks, and then use conditional statements to see which range of days contains the most-busy day

import glob

file_paths = sorted(glob.glob("exhibit-visits_city-*_varied-peak.csv"))

days_in_weeks = {
    "week 3": range(14, 21),
    "week 4": range(21, 28),
    "week 5": range(28, 35),
}

i_city_no = len("exhibit-visits_city-")
for file_path in file_paths:
    city_number = int(file_path[i_city_no : i_city_no + 1])
    data = numpy.loadtxt(fname=file_path, delimiter=",")
    daily_total = numpy.sum(data, axis=0)
    most_busy_day = numpy.argmax(daily_total)

    for week_name, days_in_week in days_in_weeks.items():
        if most_busy_day in days_in_week:
            print(f"City {city_number} had their top day in {week_name}")
City 7 had their top day in week 4
City 8 had their top day in week 5
City 9 had their top day in week 4

This illustrates the use of conditional statements in nested loops. But there’s an easier way to accomplish this task

import glob

file_paths = sorted(glob.glob("exhibit-visits_city-*_varied-peak.csv"))

i_city_no = len("exhibit-visits_city-")
for file_path in file_paths:
    city_number = int(file_path[i_city_no : i_city_no + 1])
    data = numpy.loadtxt(fname=file_path, delimiter=",")
    daily_total = numpy.sum(data, axis=0)
    most_busy_day = numpy.argmax(daily_total)
    week_number = (most_busy_day // 7) + 1

    print(f"City {city_number} had their top day in week {week_number}")
City 7 had their top day in week 4
City 8 had their top day in week 5
City 9 had their top day in week 4

Challenge: How Many Paths?

Consider this code:

if 4 > 5:
    print('A')
elif 4 == 5:
    print('B')
elif 4 < 5:
    print('C')

Which of the following would be printed if you were to run this code? Why did you pick this answer?

  1. A
  2. B
  3. C
  4. B and C

Solution

C gets printed because the first two conditions, 4 > 5 and 4 == 5, are not true, but 4 < 5 is true. In this case only one of these conditions can be true for at a time, but in other scenarios multiple elif conditions could be met. In these scenarios only the action associated with the first true elif condition will occur, starting from the top of the conditional section. A flowchart diagram of a conditional section with multiple elif conditions and some possible outcomes. This contrasts with the case of multiple if statements, where every action can occur as long as their condition is met. A flowchart diagram of a conditional section with multiple if statements and some possible outcomes.

Challenge: What Is Truth?

True and False booleans are not the only values in Python that are true and false. In fact, any value can be used in an if or elif. After reading and running the code below, explain what the rule is for which values are considered true and which are considered false.

if '':
    print('empty string is true')
if 'word':
    print('word is true')
if []:
    print('empty list is true')
if [1, 2, 3]:
    print('non-empty list is true')
if 0:
    print('zero is true')
if 1:
    print('one is true')

zzzz Challenge: That’s Not Not What I Meant

Sometimes it is useful to check whether some condition is not true. The Boolean operator not can do this explicitly. After reading and running the code below, write some if statements that use not to test the rule that you formulated in the previous challenge.

if not '':
    print('empty string is not true')
if not 'word':
    print('word is not true')
if not not True:
    print('not not True is true')

Challenge: Close Enough

Write some conditions that print True if the variable a is within 10% of the variable b and False otherwise. Compare your implementation with your partner’s: do you get the same answer for all possible pairs of numbers?

Hint

There is a built-in function abs that returns the absolute value of a number:

print(abs(-12))
12

Solution 1

a = 5
b = 5.1

if abs(a - b) <= 0.1 * abs(b):
    print('True')
else:
    print('False')

Solution 2

print(abs(a - b) <= 0.1 * abs(b))

This works because the Booleans True and False have string representations which can be printed.

Challenge: Sorting a List Into Buckets

We’d like to break our list of files into three lists called city_files, yearly_files, and other_files, respectively.

Add code to the template below to do this. Note that the string method startswith returns True if and only if the string it is called on starts with the string passed as an argument, that is:

'String'.startswith('Str')
True

But

'String'.startswith('str')
False

Use the following Python code as your starting point:

filenames = [
    "exhibit-visity_city-3.csv",
    "exhibit-visity_city-4.csv",
    "exhibit-visity_year-1_city-1.csv",
    "exhibit-visity_year-2_city-1.csv",
    "exhibit-visity_city-2.csv",
    "sandbox.py",
]
city_files = []
yearly_files = []
other_files = []

Your solution should:

  1. loop over the names of the files
  2. figure out which group each filename belongs in
  3. append the filename to that list

In the end the three lists should be:

city_files: ['exhibit-visity_city-3.csv', 'exhibit-visity_city-4.csv', 'exhibit-visity_city-2.csv']
yearly_files: ['exhibit-visity_year-1_city-1.csv', 'exhibit-visity_year-2_city-1.csv']
other_files: ['sandbox.py']

Solution

for filename in filenames:
    if filename.startswith("exhibit-visity_city"):
        city_files.append(filename)
    elif filename.startswith("exhibit-visity_year"):
        yearly_files.append(filename)
    else:
        other_files.append(filename)

print("city_files:", city_files)
print("yearly_files:", yearly_files)
print("other_files:", other_files)

Challenge: Counting Vowels

  1. Write a loop that counts the number of vowels in a character string.
  2. Test it on a few individual words and full sentences.
  3. Once you are done, compare your solution to your neighbor’s. Did you make the same decisions about how to handle the letter ‘y’ (which some people think is a vowel, and some do not)?

Solution

vowels = 'aeiouAEIOU'
sentence = 'Mary had a little lamb.'
count = 0
for char in sentence:
    if char in vowels:
        count += 1

print('The number of vowels in this string is ' + str(count))

Key points

  • Use if condition to start a conditional statement, elif condition to provide additional tests, and else to provide a default.
  • The bodies of the branches of conditional statements must be indented.
  • Use == to test for equality.
  • X and Y is only true if both X and Y are true.
  • X or Y is true if either X or Y, or both, are true.
  • Zero, the empty string, and the empty list are considered false; all other numbers, strings, and lists are considered true.
  • True and False represent truth values.

View in GitHub

Loading last updated date...