Filtering, Sorting & Grouping
Ask real questions of your data — boolean masks, combined conditions, isin and between, loc vs iloc, sort_values, groupby aggregation, and pivot tables.
A DataFrame you can only look at is a spreadsheet. A DataFrame you can query is a superpower. This lesson covers the operations that answer real questions: "which orders were over $50?", "what's the average rating per genre?", "who are our top five customers?" — all without a single loop.
We'll use one small cereal-style dataset throughout, so each cell is self-contained.
Boolean masks: filtering rows
The pattern is the one you met with NumPy: build a Series of True/False,
then use it to index the DataFrame:
Read df[df["rating"] > 50] inside-out: the inner expression makes a boolean
mask, the outer brackets keep only the True rows.
Combining conditions: the parentheses gotcha
Multiple conditions use & (and), | (or), and ~ (not) — not Python's
and/or/not. And each condition must be wrapped in parentheses,
because & binds tighter than >:
The classic error
df[df["sugars"] < 5 & df["rating"] > 40] — without parentheses — raises a
confusing ValueError about "truth value of a Series is ambiguous", because
Python evaluates 5 & df["rating"] first. When you see that error, check your
parentheses (and that you used &/|, not and/or).
isin, between, and string filters
Three shortcuts save you from long chains of |:
The .str accessor exposes most Python string methods (contains, startswith,
lower, split, …) applied to every value at once — vectorized, like everything
else.
loc vs iloc
Both select rows and columns, but by different coordinates:
.loc[rows, cols]— by label (index values, column names); slices are inclusive.iloc[rows, cols]— by integer position; slices exclude the end, like Python lists
That last pattern — df.loc[mask, column] — is also the safe way to modify
a filtered subset (plain chained indexing like df[mask][col] = ... triggers
the infamous SettingWithCopyWarning).
Sorting
sort_values orders rows by one or more columns:
groupby: split, apply, combine
groupby is the single most important pandas operation. It splits the
table into groups, applies an aggregation to each, and combines the
results into a new table:
The named-aggregation form — new_name=("column", "function") — keeps the
output tidy and self-documenting.
pivot_table: groupby in two dimensions
When you want groups along both axes (rows and columns), reach for
pivot_table:
Each cell is the mean rating for one (manufacturer, type) combination — the
same result as groupby(["mfr", "type"]), just reshaped into a grid that's
much easier to scan (and to feed into a heatmap, as you'll see in the seaborn
lesson).
Check your understanding
Q1.Why does df[df.sugars < 5 & df.rating > 40] raise an error?
Q2.Which expression keeps rows where mfr is either "K" or "N"?
Q3.What's the key difference between .loc and .iloc slicing?
Q4.df.groupby("mfr")["rating"].mean() implements which pattern?
Q5.When is pivot_table more convenient than a plain groupby?
Exercise: Query an orders table
Build an orders DataFrame with columns city (3 cities, 10 rows), payment
("card", "cash", "e-wallet"), and amount. Then answer: (1) which orders
exceed 100? (2) which are card orders over 100 (two conditions)? (3) for
each city, how many orders, total, and average amount (one groupby().agg())?
(4) build a pivot_table of total amount by city × payment method.
You can now slice, dice, and summarize tables — next we make the numbers visible with Matplotlib.