pandas·Lesson 6·10 min·0/3 exercises

Filtering rows with a boolean mask

Why df[df["cups"] > 100] works, and why the index comes out full of holes.

df[mask]Series comparison&|~.isin().iloc.reset_index()

Watch it happen

Play it through, or step back and forth yourself.

df
city
item
cups
revenue
0
Delhi
masala
120
2400.0
1
Mumbai
ginger
80
2000.0
2
Delhi
Ginger
95
1852.5
3
Pune
masala
150
3000.0
4
Mumbai
masala
60
NaN
5
Delhi
elaichi
110
2530.0

Same six rows. We want only the busy days — the ones where we sold more than 100 cups.

The idea

The line df[df["cups"] > 100] looks like it's doing something clever. It isn't — it's doing two boring things back to back, and the only reason it reads strangely is that both happen on one line.

First, df["cups"] > 100 compares an entire column at once and hands back a Series of True/False, one per row. That's the boolean mask. Second, putting a boolean Series inside df[...] means "keep the rows where this is True". Split it across two lines and it stops looking like magic:

busy = df["cups"] > 100   # a Series of True/False
df[busy]                  # the rows where it's True

The index does not renumber

This is the part that catches people. Filtering keeps the original row labels. Drop rows 1, 2 and 4 and what's left is labelled 0, 3, 5 — not 0, 1, 2. The rows kept their names when they moved.

So result[1] raises KeyError: there's no row labelled 1 any more. If you want "the second row, whatever it's called", ask by position with result.iloc[1]. If you genuinely want fresh labels, say so explicitly with result.reset_index(drop=True). Both are fine; picking one by accident is not.

Hand-drawn notes showing that filtering keeps the original row labels, leaving gaps, so looking up by label after a filter can raise a KeyError.

Combining conditions

Two traps here, and they bite in the same line of code. Use &, | and ~ — not and, or, not. The Python keywords want a single true-or-false answer and a mask has hundreds, so pandas raises rather than guess. And wrap each condition in parentheses, because & binds tighter than > in Python:

df[(df["city"] == "Delhi") & (df["cups"] > 100)]   # correct
df[df["city"] == "Delhi" & df["cups"] > 100]      # TypeError

For a long list of allowed values, don't chain a dozen |s — df[df["city"].isin(["Delhi", "Pune"])] says the same thing and reads better.

See it run

The lesson's code, ready to run and to fiddle with.

Putting the kettle on…

Starting up…

Worked example

not graded

Already written and ready to go — press Run to see what it does, then change a number, a column name, anything, and run it again.

tryprinting the mask on its own — it is just another Series.

Press Run — the output appears here.

Your turn

3 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.

Keep only the rows where revenue is 2000 or more.

your answer

Keep only the rows from Delhi.

your answer

Now both at once: rows from Delhi and with more than 100 cups.

your answer