Written and maintained by CASRAI Editorial Board
Last updated
numpy.where picks values from one of two arrays depending on a True/False condition, element by element. Called with three arguments, np.where(condition, x, y) returns a new array with elements from x where condition is True and from y elsewhere. Called with only a condition, it returns the positions where the condition is True. For three or more outcomes, np.select is the cleaner tool, and for plain filtering the NumPy documentation prefers nonzero or boolean indexing.
What np.where is used for in research
In research data work, np.where is the vectorised “if/else”: it recodes a variable in one step, with no loop. Typical uses are replacing a sentinel code with np.nan, capping or flagging values above a threshold, and creating a binary indicator from a continuous measure. It sits in the recoding stage of a data cleaning workflow and is one of the basic operations behind data wrangling for research.
The signature in the NumPy manual (v2.5) is numpy.where(condition, [x, y, ]/). The arguments are positional-only, so write them without keywords. The manual describes condition as a boolean array_like and states that “x, y and condition need to be broadcastable to some shape.”
Install or access
The NumPy installation page states that the only prerequisite is Python itself. Any one of these official commands installs it:
pip install numpyconda install numpyuv pip install numpypixi add numpy
If you work in an isolated environment, create it first with python -m venv my-env, then activate it with source my-env/bin/activate (macOS and Linux) or my-env\Scripts\activate (Windows). If you prefer a notebook interface, see Anaconda for Jupyter Notebook. Check the install with:
import numpy as np
print(np.__version__)
Step-by-step: using np.where
1. Replace values with np.where(condition, x, y)
This is the example in the NumPy manual. Values below 5 are kept and the rest are multiplied by 10:
import numpy as np
a = np.arange(10)
np.where(a < 5, a, 10*a)
# array([ 0, 1, 2, 3, 4, 50, 60, 70, 80, 90])
A scalar works as x or y because of broadcasting. The manual’s 2-D example replaces every element of 4 or more with -1:
a = np.array([[0, 1, 2], [0, 2, 4], [0, 3, 6]])
np.where(a < 4, a, -1)
# array([[ 0, 1, 2],
# [ 0, 2, -1],
# [ 0, 3, -1]])
A research-style use is converting a sentinel code to a missing value. The array below is illustrative, with -999.0 standing in for “not recorded”:
d = np.array([4.2, -999.0, 5.1, -999.0])
np.where(d == -999.0, np.nan, d)
# array([4.2, nan, 5.1, nan])
2. Use np.where with multiple conditions
Python’s and and or do not work on arrays, so combine conditions with the array operators. The numpy.logical_and page says that “the & operator can be used as a shorthand for np.logical_and on boolean ndarrays”, and the numpy.logical_or page says the same of | and np.logical_or. Put each comparison in its own parentheses, because in Python the & and | operators bind more tightly than comparisons such as > (see the operator precedence table in the Python language reference):
v = np.arange(5)
np.where((v > 1) & (v < 4), 1, 0)
# array([0, 0, 1, 1, 0])
np.where((v < 1) | (v > 3), 'edge', 'mid')
# array(['edge', 'mid', 'mid', 'mid', 'edge'], dtype='<U4')
The manual’s own logical_and example, np.logical_and(x > 1, x < 4) with x = np.arange(5), returns array([False, False, True, True, False]). That boolean array is exactly what np.where receives as its condition, so np.where(np.logical_and(v > 1, v < 4), 1, 0) gives the same result as the & version above. Note that bitwise_and is a separate function.
3. Handle three or more outcomes: np.select
Nesting np.where calls works, but np.select(condlist, choicelist, default=0) states the cases side by side. The manual specifies three rules: when multiple conditions are satisfied, “the first one encountered in condlist is used”; choicelist “has to be of the same length as condlist“; and default is “the element inserted in output when all conditions evaluate to False.” The manual’s example:
x = np.arange(6)
np.select([x < 3, x > 3], [-x, x**2], 42)
# array([ 0, -1, -2, 42, 16, 25])
The nested equivalent, np.where(x < 3, -x, np.where(x > 3, x**2, 42)), returns the same array. The np.select form keeps the order of precedence visible, which matters when cases overlap.
4. Get positions with np.where(condition) only
With one argument, the manual says the function “is a shorthand for np.asarray(condition).nonzero(). Using nonzero directly should be preferred, as it behaves correctly for subclasses.” The result is a tuple of arrays, one per dimension. With the numpy.nonzero page’s array:
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
np.nonzero(a > 3)
# (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))
The first array holds row indices and the second holds column indices. If you only want the values, the nonzero page recommends boolean indexing, a[a > 3], instead.
Which function to choose
| Situation | Function | What the NumPy manual says |
|---|---|---|
| Two outcomes per element | np.where(cond, x, y) |
Elements from x where True, from y elsewhere |
| Three or more outcomes | np.select(condlist, choicelist, default) |
First matching condition in condlist is used; default fills the rest |
| Positions of True values | np.nonzero(cond) |
Preferred over one-argument np.where; returns a tuple of arrays, one per dimension |
| Only the matching values | a[a > 3] |
Recommended on the nonzero page for plain filtering |
Output and how to read it
The three-argument form returns an ndarray of the broadcast shape, with no change to the inputs. A mental model from the manual is the 1-D list comprehension [xv if c else yv for c, xv, yv in zip(condition, x, y)]: for each position, take x if the condition is True there, else y.
Broadcasting extends this to arrays of different shapes. The manual’s example uses x, y = np.ogrid[:3, :4], a column of 3 and a row of 4:
np.where(x < y, x, 10 + y)
# array([[10, 0, 0, 0],
# [10, 11, 1, 1],
# [10, 11, 12, 2]])
Each cell compares its row value x with its column value y. Where x < y it shows x, and otherwise 10 + y. With a boolean condition and explicit arrays, np.where([[True, False], [True, True]], [[1, 2], [3, 4]], [[9, 8], [7, 6]]) returns array([[1, 8], [3, 4]]).
Troubleshooting
- ImportError “Importing the numpy c-extensions failed”. The NumPy install page links its ImportError troubleshooting guide for this message.
- You get a tuple of arrays instead of values. That is the one-argument form returning indices. Pass
xandyfor values, or usea[condition]. - Multiple conditions do not combine as expected. Use
&and|(ornp.logical_andandnp.logical_or) with each comparison in parentheses, notandandor. - Shapes do not match.
x,yandconditionmust be broadcastable to a common shape.
For another NumPy function used to build arrays to test, see NumPy linspace. If the array holds column data, renaming columns in a pandas DataFrame is a common next step.
Free alternatives
All of these ship with NumPy, which is free to install from the commands above:
| Function | Use it when | Source |
|---|---|---|
| numpy.where | Choosing between two arrays on a condition | NumPy manual |
| numpy.select | Several conditions with an explicit default | NumPy manual |
| numpy.nonzero | You need indices of True values | NumPy manual |
| numpy.logical_and | Combining conditions without the & operator | NumPy manual |
FAQ
How does Python numpy where work?
After import numpy as np, np.where(condition, x, y) returns an array with elements from x where the condition is True and from y elsewhere. With only condition, it returns the indices of True elements as a tuple of arrays.
How do I use numpy where with multiple conditions?
Combine boolean arrays with & (and) or | (or), wrapping each comparison in parentheses, for example np.where((v > 1) & (v < 4), 1, 0). For three or more distinct outcomes, use np.select, where the first matching condition wins.
Should I use np.where or np.nonzero to find indices?
The NumPy manual says that using nonzero directly should be preferred, because it behaves correctly for subclasses.
Sources
- NumPy manual (v2.5), numpy.where, checked 2026-10-29.
- NumPy manual, numpy.select, numpy.nonzero, numpy.logical_and and numpy.logical_or, checked 2026-10-29.
- NumPy, Installing NumPy, checked 2026-10-29.
- Python, Expressions (operator precedence), checked 2026-10-29.








