Boolean masks
Selecting by condition — and why the answer comes back flat.
a > na[mask]&|~.sum().any().all()np.count_nonzeroWatch it happen
Play it through, or step back and forth yourself.
cupscups again — four days by three stalls. We want the busy ones: everything above 100 cups.
The idea
Comparing an array to a number compares every element and hands back an array of the same shape full of True and False. That's a boolean mask, and its dtype is bool — one byte per element.
Put the mask in the brackets and you get the elements sitting under a True.
The result is 1-D
cups[cups > 100] on a (4, 3) array gives shape (5,) — not a smaller rectangle. It has to. The surviving cells are scattered; they don't form a rectangle, and unlike pandas there's no index to record where the holes were. So NumPy flattens.
If you want the shape preserved, don't select — replace. That's np.where, and it gets the lesson after next.

Combining conditions
Two traps, both in the same line of code. Use &, | and ~ — not and, or, not, which demand a single true-or-false answer and can't get one from an array. And parenthesise each condition, because & binds tighter than >:
cups[(cups > 90) & (cups < 130)] # correct
cups[cups > 90 & cups < 130] # ValueErrorFor a list of allowed values, np.isin beats a chain of |:
cups[np.isin(cups, [60, 90, 120])]
Masks are numbers too
True is 1, so a mask supports arithmetic — and that gives you counting for free:
(cups > 100).sum() # how many match
(cups > 100).sum(axis=0) # how many per column
(cups > 100).any() # at least one?
(cups > 100).all() # every one?
np.count_nonzero(cups > 100) # the same count, stated plainly.any() and .all() take an axis too, which is often exactly what you want: "which rows have any missing value?" is np.isnan(x).any(axis=1).
Masks select rows, as well as elements
A 1-D mask whose length matches an axis selects along that axis, and this form keeps the rectangle:
busy = cups.sum(axis=1) > 300 # one True/False per day, shape (4,)
cups[busy] # the matching rows — still 2-DThat's the pattern you'll use constantly on real data: build a per-row condition, then use it to keep rows. It stays rectangular because you're selecting whole rows, not scattered cells.
Finally, masks work on the left of an assignment too — cups[cups < 70] = 70 edits in place. Powerful, and it changes the original array along with every view of it.
Practice
Write it yourself. The answer is there when you want it.
Putting the kettle on…
Starting up…
Write it yourself
not gradedBuild the mask cups > 100 and print it. Then print what it selects and the shape of that selection, how many passed in total, and how many per stall with axis=0. Finish with a per-row mask instead — days selling more than 300 cups altogether — and use it to keep whole rows.
Your turn
4 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.
Return every value in cups below 90.
How many values in cups are at least 100? Return the count.
Return the values in cups that are between 90 and 130 — greater than 90 and less than 130.
Keep only the rows of cups whose total is more than 300. The result should still be 2-D.
