Skip to content

Boolean indexing

Boolean indexing selects observations with a True/False mask. Learn NumPy filtering, selection copies, masked assignment and the danger of stale observation order.

Boolean indexing selects observations using a mask of True and False values. In a quant workflow, a mask can retain eligible instruments, finite observations or scenarios that breach a limit. The condition defines the sample: a statistic computed after filtering describes the retained observations.
In NumPy, a one-dimensional Boolean mask selects the positions marked True, preserving their order. It is a form of advanced array indexing.

From a condition to a selection

These fictional prices are USD per share. Retain prices strictly above 100:

import numpy as np prices = np.array([98, 101, 105, 99]) mask = prices > 100 selected = prices[mask] print(mask.tolist()) # [False, True, True, False] print(selected.tolist()) # [101, 105] print(int(selected.sum())) # 206

The comparison creates the mask; the brackets perform the selection. Positions 1 and 2 survive, using Python's zero-based indexing. Their prices sum to 206; this is a selection check, not a portfolio valuation.

Four fictional prices of 98, 101, 105 and 99 USD per share produce the mask False, True, True, False for prices greater than 100. Positions 1 and 2 select 101 and 105 in their original order.
Four fictional prices of 98, 101, 105 and 99 USD per share produce the mask False, True, True, False for prices greater than 100. Positions 1 and 2 select 101 and 105 in their original order.

Original deterministic illustration. Prices are stipulated USD per share; the threshold is strictly greater than 100. The mask and prices share the same observation order.

Reading a selection and assigning through a mask

A NumPy Boolean selection returns a copy of the array data. Changing that selected numerical array does not change the source. Direct masked assignment, however, writes into the source:
import numpy as np prices = np.array([98, 101, 105, 99]) mask = prices > 100 selected = prices[mask] selected[0] = 0 print(prices.tolist()) # [98, 101, 105, 99] print(selected.tolist()) # [0, 105] prices[mask] = 0 print(prices.tolist()) # [98, 0, 0, 99]
Here zero is an artificial replacement chosen to expose mutation, not a price-cleaning recommendation. Writing prices[mask][0] = 0 instead changes a temporary selection copy and leaves prices unchanged.

A valid shape can still select the wrong observations

For this one-dimensional example, the mask must have the same length as the array. That check alone cannot establish that the observations match. A NumPy array carries no instrument or date labels: a mask belongs to the ordering from which it was constructed.
import numpy as np prices = np.array([98, 101, 105, 99]) mask = prices > 100 reordered = np.sort(prices) print(reordered.tolist()) # [98, 99, 101, 105] print(reordered[mask].tolist()) # [99, 101] print(reordered[reordered > 100].tolist()) # [101, 105]

The stale mask still selects positions 1 and 2, even though their contents changed. Recompute the condition after reordering, or move the observations and their mask together. The same discipline applies when using a price-derived mask on a separate array of positions: both arrays must describe the same instruments in the same order.

Combine conditions explicitly

For Boolean arrays, use parenthesised comparisons with & for elementwise AND, | for OR and ~ for complement. For example, (prices > 100) & (prices <= 103) retains only 101 from the original prices. Python's and, or and not attempt a truth test of the whole array; a multi-element NumPy array raises an ambiguous-truth-value error.
Choose a missing-data policy explicitly. For floating-point data, np.isfinite(values) builds a mask that excludes both NaN and positive or negative infinity. A threshold test by itself does not establish data validity.
The examples were executed with Python 3.14.4 and NumPy 2.5.1. For a financial application of masks, see Vectorisation, especially “Masks instead of branchy loops” (public preview; full lesson requires membership).

Sources

Last updated
  • numpy
  • boolean masks
  • array indexing
  • data alignment
← Back to the glossaryBack to top ↑