🚀 Supercharge your YouTube channel's growth with AI.
Try YTGrowAI Freenp.where in Python: Find Indices and Replace Values with numpy.where()

Call np.where with only a condition and it answers with a tuple of index positions, not the values themselves. That shape catches you on the first line you print, and the trailing comma inside the parentheses is the clue to why. With numpy.where(), a missing reading can become zero if you choose the wrong fallback, so keep the condition separate from the replacement policy.
How np.where chooses between indices and values
Start with synthetic sensor readings, including one missing measurement represented by NaN. Run the snippets in order in a Python session with NumPy installed and use the commented output to check each result.
import numpy as np
readings = np.array([12.0, 41.5, 8.25, 55.0, 41.5, np.nan])
high = readings > 40
print(readings)
print(high)
# Captured output
# [12. 41.5 8.25 55. 41.5 nan]
# [False True False True True False]
Comparing the array with 40 creates a boolean mask with True or False for each reading.
The missing measurement produces False here, which only means it didn’t satisfy this comparison.
print(np.where(high))
print(np.where(high, readings, 0.0))
# Captured output
# (array([1, 3, 4]),)
# [ 0. 41.5 0. 55. 41.5 0. ]
Passing that mask alone requests positions, counted from zero. Adding readings and 0.0 requests a replacement array instead.
The tuple contains positions 1, 3 and 4, whereas the replacement has six elements. Its final zero erased the missing reading.
flags = np.where(high, 1, 0)
print(flags)
print(flags.dtype)
print(readings)
# Captured output
# [0 1 0 1 1 0]
# int64
# [12. 41.5 8.25 55. 41.5 nan]
Choose integer alternatives when you need flags rather than measurements. Both alternatives determine the output dtype independently of the array that produced the mask. The NumPy reference requires both replacement arguments together.
Find matching indices in one or two dimensions
The trailing comma describes a tuple containing one index array. Keep that tuple when retrieving matching values, because NumPy accepts it directly as an index.
indices = np.where(high)
print(indices)
print(indices[0])
print(readings[indices])
# Captured output
# (array([1, 3, 4]),)
# [1 3 4]
# [41.5 55. 41.5]
Extracting indices[0] gives the plain position array for this one-dimensional input.
The repeated 41.5 survives twice because each matching position is retained.
grid = readings.reshape(2, 3)
rows, columns = np.where(grid > 40)
print(rows)
print(columns)
print(grid[rows, columns])
# Captured output
# [0 1 1]
# [1 0 1]
# [41.5 55. 41.5]
Reshaping the readings into two rows changes how positions are described. A match now needs both a row and a column, so unpack the result into two equal-length arrays.
Pair entries by position across those arrays: (0, 1), (1, 0) and (1, 1).
missing = np.where(readings > 100)
print(missing)
print(readings[missing])
print(high.nonzero())
# Captured output
# (array([], dtype=int64),)
# []
# (array([1, 3, 4]),)
A search can succeed without finding matches. Raising the threshold above every reading returns an empty index array inside the same tuple structure. The final nonzero() call returns the same positions, and NumPy recommends it for subclasses because one-argument where converts its condition with asarray.

Replace values with np.where and broadcasting
Replacement arguments describe alternatives at each output position. A scalar such as 0.5 supplies the same candidate everywhere.
replacement = np.where(high, 0.5, 0)
print(replacement)
print(replacement.dtype)
# Captured output
# [0. 0.5 0. 0.5 0.5 0. ]
# float64
The result is float64 because the alternatives include a floating-point value.
Changing the condition changes which elements you select. It doesn’t make different positions store different numeric dtypes.
fallback = np.array([10., 11., 12., 13., 14., 15.])
print(np.where(high, fallback, readings))
# Captured output
# [12. 11. 8.25 13. 14. nan]
When replacements depend on position, pass one candidate per reading. Here fallback supplies the candidate at each matching position.
Positions 1, 3 and 4 become 11, 13 and 14. The missing measurement survives because its condition is False.
per_column = np.array([10., 20., 30.])
print(np.where(grid > 40, per_column, grid))
print(grid.shape, per_column.shape)
# Captured output
# [[12. 20. 8.25]
# [10. 20. nan]]
# (2, 3) (3,)
For the reshaped grid, one replacement row can apply to both rows. Broadcasting aligns dimensions from the right, requiring matching sizes or a size of one. The length-three array therefore aligns with the three columns, while a length-two array would need reshaping to express per-row logic.
numpy where multiple conditions with &, | and ~
Combine array comparisons with & for elementwise AND, | for OR and ~ to invert a mask. Parenthesize each comparison first, because Python gives bitwise operators higher precedence than comparisons.
print(np.where(readings > 10 & readings < 40))
# Captured exception (final traceback line)
# TypeError: ufunc 'bitwise_and' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
This expression fails before np.where receives a condition. Python attempts 10 & readings first, which fails because a bare integer cannot combine bitwise with a float array.
Put each comparison in parentheses to create boolean arrays before applying &. The inclusive bounds below accept 10 through 40.