Module 4 · Python for Data Analytics
Filtering and sorting rows
Keep only the rows you need with boolean conditions, combine conditions with & and |, use isin, between and text matching, and sort or pick the top rows.
About 20 minutes
The problem
The finance manager has three quick requests for Bisi:
"Which order lines had a 10% discount and more than 25 cartons? Show me our Lagos supermarkets. And what were the five biggest order lines in June 2026?"
Each one means keeping only the rows that meet a condition, and sometimes putting them in order. In Excel you'd click through filter menus and start again for the next question. In pandas each request is one line you can re-run, change and keep.
The concept
A condition gives a True/False for every row
orders["discount_pct"] == 10That doesn't filter anything yet: it returns a Series of 4,266 True/False values, one per row. It's called a boolean mask. Put the mask inside square brackets and pandas keeps the True rows:
big_discounts = orders[orders["discount_pct"] == 10]Combining conditions
| Meaning | pandas | Note |
|---|---|---|
| and | & | both must be true |
| or | | | either can be true |
| not | ~ | flips True and False |
Each condition needs its own brackets, because & and | are worked out before == and >:
orders[(orders["discount_pct"] == 10) & (orders["quantity"] > 25)]Without the inner brackets you get a confusing error about "truth value of a Series is ambiguous". When you see it, check your brackets.
Shortcuts for common conditions
- One of several values:
customers["region"].isin(["Lagos", "South West"]) - A range, ends included:
orders["quantity"].between(10, 20) - Text:
customers["customer_name"].str.contains("Wholesale"),.str.startswith("Ada"). Addcase=Falseto ignore capitals. - Missing values:
.isna()and.notna().
Dates stored as text in YYYY-MM-DD form compare correctly as text, so orders["order_date"] >= "2026-06-01" works even before you convert dates (lesson 5).
Choosing rows and columns together: .loc
orders.loc[mask, ["order_id", "quantity"]] keeps the rows where the mask is True and only the columns you list. It's the clearest way to say "these rows, these columns", and the safe way to change values in a filtered part of a table.
Sorting
orders.sort_values("quantity", ascending=False): largest first.- Several columns:
sort_values(["region", "credit_limit"], ascending=[True, False]). orders.nlargest(5, "quantity")andnsmallestare shortcuts for "sort and take the top 5".
Counting what's left
len(df) is the number of rows. Because True counts as 1, mask.sum() counts the matching rows without making a new table.
Example
Request 1: 10% discount and more than 25 cartons.
import pandas as pd
base = "https://academy.cloudtechanalytics.com/datasets/sales/"
orders = pd.read_csv(base + "orders.csv")
customers = pd.read_csv(base + "customers.csv")
big_discounts = orders[(orders["discount_pct"] == 10) & (orders["quantity"] > 25)]
len(big_discounts)95Request 2: Lagos supermarkets, only the useful columns, biggest credit limits first.
lagos_supermarkets = customers.loc[
(customers["region"] == "Lagos") & (customers["channel"] == "Supermarket"),
["customer_name", "city", "credit_limit"],
].sort_values("credit_limit", ascending=False)
lagos_supermarkets.head()customer_name city credit_limit
38 Ada Supermarket Ikeja 2000000
83 Olumide Superstore Lekki 1950000
86 Yakubu Superstore Festac Festac 1550000
22 Emeka Supermarket Ikeja 1450000
68 Mama Nkechi Mart Festac 1250000Request 3: the five biggest order lines in June 2026, by quantity.
june_2026 = orders[orders["order_date"].between("2026-06-01", "2026-06-30")]
june_2026.nlargest(5, "quantity")Walkthrough
- Load
ordersandcustomersas in the Example. - Run
orders["discount_pct"] == 10on its own and look at the result: a column of True and False. Then run(orders["discount_pct"] == 10).sum()to count the 10% lines (525). - Run the Request 1 filter, then remove the inner brackets and run it again to see the "ambiguous" error. Put them back.
- Count lines that were not discounted:
(~(orders["discount_pct"] > 0)).sum().~flips the condition. (orders["discount_pct"] == 0gives the same answer more simply.) - Use
isin:customers[customers["region"].isin(["North West", "North Central"])]lists the northern customers. - Search text:
customers[customers["customer_name"].str.contains("wholesale", case=False)]. - Run Request 3 and check the dates in the result are all in June 2026.
Practice
Practice
How many order lines in 2026 had 20 or more cartons?
Practice
How many customers are in the North West or North Central regions with a credit limit of at least ₦1,000,000?
Practice
Which customer (customer_name) has the highest credit limit in the South East region?
Challenge
Challenge · optional
In the HR dataset's employees.csv, how many employees resigned (status Resigned) within two years of being hired? Compare exit_date with hire_date: an exit_date before the hire_date's second anniversary counts. Hint: dates as text can't be added to, so convert both with pd.to_datetime and add pd.DateOffset(years=2).
More practice
Optional drills on a different dataset: the HR data. Load it with employees = pd.read_csv("https://academy.cloudtechanalytics.com/datasets/hr/employees.csv").
Drill · optional
How many Active employees earn more than ₦800,000 a month?
Drill · optional
Who was the most recent person hired into the Finance department? Give their full_name.
Check your understanding
Answer every question to check.