Typorithm · easy

Boolean masks and compound selection

pythonnumpynumerical-computingindependent-practice
Saved on this device
Full lesson · 4 learning steps Open any exercise for focused practice
1

Step 1 of 4 · intro card

Boolean masks and compound selection

0%

Concept and contract

Combine elementwise conditions with explicit parentheses and preserve the order of selected observations.

A boolean mask is an array of yes-or-no decisions aligned to the data it selects. A mask with one entry per observation can choose matching values without a Python loop. The condition must refer to the same array and population as the returned values. This lesson selects finite measurements at or above a lower bound and strictly below an upper bound, preserving their original order.

Array conditions use elementwise operators such as & and |. Python and and or try to interpret an entire array as one truth value, which is ambiguous for multiple elements. Parentheses around each comparison also matter because operator precedence is not the same as a sentence in ordinary language.

Mechanism and worked example

The worked example first converts a vector to float64 and validates that both bounds are finite and correctly ordered.

The worked example first converts a vector to float64 and validates that both bounds are finite and correctly ordered. It builds one combined mask from isfinite and the two comparisons, then selects data[mask]. That final indexing operation produces a new array. Missing values represented as None become NaN during the explicit numeric conversion and are excluded rather than counted as zero.

The boolean array and numerical values have equal shape. Inspect them side by side for a small example: each True retains the value at the same coordinate. A mask with a different length is not an invitation to guess alignment; it violates the indexing contract.

Complete worked example

python

import numpy as np

def inspect_example(values, low, high):
    data = np.asarray(values, dtype=np.float64)
    if data.ndim != 1 or not np.isfinite([low, high]).all() or low > high:
        raise ValueError("expected a vector and ordered finite bounds")
    mask = np.isfinite(data) & (data >= low) & (data < high)
    return data[mask]
Reasoning
The worked example first converts a vector to float64 and validates that both bounds are finite and correctly ordered. It builds one combined mask from isfinite and the two comparisons, then selects data[mask]. That final indexing operation produces a new array. Missing values represented as None become NaN during the explicit numeric conversion and are excluded rather than counted as zero. The boolean array and numerical values have equal shape. Inspect them side by side for a small example: each True retains the value at the same coordinate. A mask with a different length is not an invitation to guess alignment; it violates the indexing contract.
Open in local Python playground ↗

Focused decision: context is in the complete example

python

mask = np.isfinite(data) & (data >= low) & (data < high)
selected = data[mask]
Focused decision
Type this short numerical decision after reading its complete context. The complete imports, array construction, validation, and result checks remain in the worked example. Typing records practice; only the downloadable computer lab executes Python.

Counterexamples and common mistakes

The controlled counterexample uses a union of the lower and upper comparisons.

The controlled counterexample uses a union of the lower and upper comparisons. With a normal ordered interval, almost every finite value then matches at least one side. This is a plausible business error even though the expression is valid NumPy. Using and can instead fail before producing any mask, and missing parentheses can combine operands in an unintended order.

Do not confuse np.where with boolean selection. where can choose a value for every input position, while data[mask] changes the number of returned observations. Later lessons will cover conditional arithmetic and explain why merely placing an expression inside where does not prevent its evaluation.

Controlled mistake: inspect the failing numerical contract

python

import numpy as np

def inspect_example(values, low, high):
    data = np.asarray(values, dtype=np.float64)
    if data.ndim != 1 or not np.isfinite([low, high]).all() or low > high:
        raise ValueError("expected a vector and ordered finite bounds")
    mask = np.isfinite(data) & ((data >= low) | (data < high))
    return data[mask]
Reasoning
The controlled counterexample uses a union of the lower and upper comparisons. With a normal ordered interval, almost every finite value then matches at least one side. This is a plausible business error even though the expression is valid NumPy. Using and can instead fail before producing any mask, and missing parentheses can combine operands in an unintended order. Do not confuse np.where with boolean selection. where can choose a value for every input position, while data[mask] changes the number of returned observations. Later lessons will cover conditional arithmetic and explain why merely placing an expression inside where does not prevent its evaluation.
Open in local Python playground ↗

Independent practice

Make the interval inclusive at its upper edge.

Make the interval inclusive at its upper edge. Keep lower-edge inclusion, finite-value filtering, ordering and one-dimensional output. One comparison should change; there is no need to introduce a sort, fill missing values or modify the caller data.

Predict the new result for values exactly on both boundaries. Include a value above the interval and a missing measurement. If your solution changes which observations form the denominator in a later percentage, record that population change explicitly rather than treating an empty result as a numerical zero.

Step 1: Include values equal to the upper bound. Step 2: Retain the working imports, input validation and array shapes. Change the stated policy, run the supplied practice cases, then explain the newly accepted or rejected boundary.

Practice starter: solve before reading the solution

python

import numpy as np

def inspect_example(values, low, high):
    data = np.asarray(values, dtype=np.float64)
    if data.ndim != 1 or not np.isfinite([low, high]).all() or low > high:
        raise ValueError("expected a vector and ordered finite bounds")
    mask = np.isfinite(data) & (data >= low) & (data < high)
    return data[mask]

# Independent task: Include values equal to the upper bound.
Reasoning
Include values equal to the upper bound.
Open in local Python playground ↗
  • Hint 1: Find the comparison involving high.
  • Hint 2: Use <= for the upper edge while retaining the finite mask and both parentheses.

Solution, tests and trade-offs

The practice solution changes the strict upper comparison to an inclusive comparison.

The practice solution changes the strict upper comparison to an inclusive comparison. Boundary cases ensure that this is a deliberate interval decision and not a blanket acceptance of all finite values. Empty input returns an empty float64 vector, while invalid bounds still raise a useful ValueError before any selection is attempted.

Returning fewer observations is correct for this filtering contract. It would not be correct for a row-aligned feature transformation that must retain one output per input. Choose the operation from the required shape and alignment, then test both values and the selected population.

Practice solution and acceptance checks

python

import numpy as np

def inspect_example(values, low, high):
    data = np.asarray(values, dtype=np.float64)
    if data.ndim != 1 or not np.isfinite([low, high]).all() or low > high:
        raise ValueError("expected a vector and ordered finite bounds")
    mask = np.isfinite(data) & (data >= low) & (data <= high)
    return data[mask]
Reasoning
The practice solution changes the strict upper comparison to an inclusive comparison. Boundary cases ensure that this is a deliberate interval decision and not a blanket acceptance of all finite values. Empty input returns an empty float64 vector, while invalid bounds still raise a useful ValueError before any selection is attempted. Returning fewer observations is correct for this filtering contract. It would not be correct for a row-aligned feature transformation that must retain one output per input. Choose the operation from the required shape and alignment, then test both values and the selected population.
Open in local Python playground ↗

Interview reasoning and next step

Explain why (a >= low) & (a < high) differs from both Python and and an elementwise union.

Explain why (a >= low) & (a < high) differs from both Python and and an elementwise union. Show the mask for four concrete values, including a boundary. Discuss whether missing measurements should be excluded, rejected or imputed; that decision depends on the data contract and must not be hidden inside a convenient default.

Type the compound mask with its parentheses, then reconstruct it without answer choices on the PC. App questions use the same boundary examples. Next, inspect which forms of selection share storage and which create an independent buffer.

Optional stretch — after the core task works: Add one independently reasoned boundary case and explain its expected value before running it.

Computer practice: https://applydjinn.com/typorithm/numpy-lab-20261106.zip. Install pinned dependencies in an isolated Python environment. Run verify.py, then change the working exercise baseline and run --practice np-masks. The real NumPy arrays, numerical contracts, random state checks and temporary numeric files use owned fixtures only. No production database, feed, account or paid service is used. This lab executes Python; the PC typing trainer and native reading progress do not execute it.

Combine elementwise conditions with explicit parentheses and preserve the order of selected observations.