Quick answer: numpy.choose selects among multiple choice arrays using an integer index array. Confirm broadcast-compatible shapes, define how out-of-range indices should behave, and use where or take_along_axis when those operations communicate the intent more clearly.

numpy.choose() selects values from a list of choice arrays by using an index array. Each entry in the index array tells NumPy which choice to take at the same position.
The official NumPy documentation covers numpy.choose(), numpy.take_along_axis(), and numpy.select().
The first argument, often named a in NumPy docs, contains integer selectors. The second argument contains the choices. If a selector is 0, NumPy takes from the first choice. If a selector is 1, it takes from the second choice, and so on.
By default, choose() uses mode="raise". That means every selector must be within the available choice range. If you have three choices, valid selectors are 0, 1, and 2.
The other modes are useful when selectors may go outside that range. mode="clip" clips low values to 0 and high values to the last choice. mode="wrap" wraps selectors around the available choices.
Use choose() when selection is driven by numeric indexes. Use select() when selection is driven by multiple Boolean conditions. Use take_along_axis() when you need index-based selection along a specific axis.
Choice arrays should be broadcastable to the selector shape. The result follows the broadcast shape, so checking shapes before a complex call makes the output easier to reason about.
A common mistake is to read choose() as choosing one entire array. Instead, it chooses per position. The selector at each position decides which choice provides the value for that same position after broadcasting.
Because selector values are numeric indexes, they should be integer data. If the selector comes from user input, file data, or earlier calculations, convert and validate it before relying on the default range-checking behavior.
For readable code, name the selector array clearly. Names such as selectors, codes, or levels make it obvious that the array is driving the choice, while the list passed as the second argument holds the possible outputs.
Choose From Scalar Choices
Scalar choices broadcast across the selector array.
import numpy as np
selectors = np.array([0, 1, 2, 1, 0])
result = np.choose(selectors, [10, 20, 30])
print(result)
The selector 0 chooses 10, selector 1 chooses 20, and selector 2 chooses 30.
The result has the same shape as the selector array.
This form is useful for mapping compact integer codes to numeric values.
It is also useful for small lookup tables where a dictionary would be awkward because the input is already a NumPy array.
Choose Between Arrays
Choice arrays can hold different values at each position.
import numpy as np
selectors = np.array([0, 1, 0, 1])
low = np.array([1, 2, 3, 4])
high = np.array([10, 20, 30, 40])
result = np.choose(selectors, [low, high])
print(result)
Each selector chooses from low or high at the same position.
This is different from choosing one whole array for all positions.
The selector array and the choice arrays line up element by element.
If one of the choice arrays has the wrong shape, broadcasting rules decide whether NumPy can still align it. When the result surprises you, print the shapes of the selector and each choice first.
Use choose With A 2D Selector
choose() also works with 2D arrays.
import numpy as np
selectors = np.array([
[0, 1, 2],
[2, 1, 0],
])
result = np.choose(selectors, [100, 200, 300])
print(result)
The scalar choices broadcast to the 2D selector shape.
The output keeps the same row and column layout.
This can be useful for lookup tables, masks encoded as integers, or small category maps.
The same idea extends to larger arrays. The important rule is that every selector value refers to one of the available choices.
Clip Out Of Range Selectors
mode="clip" keeps selectors inside the valid range.
import numpy as np
selectors = np.array([-1, 0, 1, 2, 3])
result = np.choose(selectors, [10, 20, 30], mode="clip")
print(result)
The selector -1 is clipped to 0.
The selector 3 is clipped to the last available choice.
Use this mode only when clipping is the intended rule for your data.
Clipping can be sensible for capped scores, but it can be risky for category codes because a bad high code silently becomes the last category.
Wrap Out Of Range Selectors
mode="wrap" wraps selectors around the choice count.
import numpy as np
selectors = np.array([-1, 0, 1, 2, 3])
result = np.choose(selectors, [10, 20, 30], mode="wrap")
print(result)
With three choices, selector 3 wraps back to 0.
Negative selectors also wrap around the available choices.
This is useful for cyclic mappings, but it can hide bad input if wrapping was not expected.
For most data-cleaning tasks, keep the default raising behavior until you have a clear reason to accept wrapping or clipping.
Compare choose And select
Use choose() for integer selectors and select() for Boolean conditions.
import numpy as np
scores = np.array([45, 70, 88, 92])
selectors = np.array([0, 1, 1, 2])
labels = np.choose(selectors, ["low", "pass", "high"])
print(labels)
Here, the integer selectors already encode the category to use.
If you need to build categories from conditions such as scores >= 90, np.select() is often clearer.
If you need to gather values from positions along a chosen axis, reach for take_along_axis() instead. It is designed for axis-aware index lookup, while choose() selects among a list of choices.
In short, use np.choose() when each position has an integer selector, keep choice arrays broadcastable to the selector shape, and choose the range-handling mode deliberately.
Model The Choice Arrays
Each choice array supplies a candidate value for the same output positions. Keep the number, shape, dtype, and meaning of those arrays consistent before selection.
Build The Index Array
The index determines which choice is selected at each position. Validate its dtype and range, and remember that broadcasting can expand an index or choice shape in ways that are easy to miss.
Choose An Out-of-Range Mode
The default raises for invalid indices. Clip or wrap modes can be useful for controlled inputs, but they can hide upstream errors, so make the mode part of the documented contract.
Compare Alternative Operations
Use where for a binary condition, take for one-dimensional indexed selection, or take_along_axis for an axis-aware operation. The simplest primitive should match the mathematical explanation of the code.
Control Dtypes And Memory
The output dtype must represent the selected values. Large choice arrays and broadcasted intermediates can consume memory, so inspect shapes and profile before scaling up.
Test Boundaries
Test scalar and array indices, equal and broadcastable shapes, negative values, out-of-range indices, clip and wrap modes, mixed dtypes, and a hand-computed result. Assert output shape and values.
The official NumPy choose documentation defines index modes and broadcasting. Related Python Pool references include NumPy arrays and tests.
For related array selection, compare NumPy shapes, index-bound tests, and choice sequences before using choose.
Frequently Asked Questions
What does numpy.choose do?
It selects an element from one of several choice arrays for each position using an index array.
How is numpy.choose different from where?
choose selects among multiple arrays by integer index, while where expresses a condition between two choices; the clearer operation depends on the data contract.
What happens when an index is out of bounds?
The default mode raises an error, while other modes can clip or wrap indices; choose deliberately and test boundary values.
Why is the output shape unexpected?
The index and choice arrays broadcast according to NumPy rules, so inspect shapes and normalize them before selection.