Boolean masks
What it is
A comparison over an array gives a boolean array of the same shape; indexing with it returns a 1-D array of the elements where it is True.
Why it matters
It is the vectorised if: filtering, counting and conditional assignment are all the same mask expression, and mask.sum() counts the survivors before you commit to anything.
In the real world: Selecting only the transactions over ₹1,00,000 for a manual fraud review.
Visual example
Boolean indexingA boolean mask is one True/False per element; indexing with it keeps the True positions and flattens the rest away.
What the mask gives you
x[mask] → [3, 4]
mask.sum() → 2
np.nonzero(mask)[0] → [0, 2]
x[~mask] → [-1, -5]
Why this matters
Every filter, count and conditional write in NumPy is this: build a boolean array, then use it. It runs in compiled code over the whole array at once.
Common misconception
Wrong idea: the result keeps the shape, with the False positions blanked out.
Correct idea: the result is 1-D and shorter — only the True elements, positions discarded. Use np.where(mask, x, 0) to keep the shape.
- 1Compare
x > 0gives a boolean array of the same shape. - 2Index
x[mask]gathers the True positions into a new 1-D array. - 3Or assign
x[mask] = 0writes to exactly those positions, in place.
x = np.array([3, -1, 4, -5])
mask = x > 0
mask # array([ True, False, True, False])
x[mask] # array([3, 4])
mask.sum() # 2 — booleans sum as 0/1
x[x < 0] = 0 # conditional assignment in placeUsing and, or or not between masks. They call __bool__ on a whole array and raise 'truth value is ambiguous'. The element-wise operators are &, |, ~, and each comparison needs its own parentheses because & binds tighter than <.