199

NumPy has the efficient function/method nonzero() to identify the indices of non-zero elements in an ndarray object. What is the most efficient way to obtain the indices of the elements that do have a value of zero?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
gotgenes
  • 38,661
  • 28
  • 100
  • 128

9 Answers9

301

numpy.where() is my favorite.

>>> x = numpy.array([1,0,2,0,3,0,4,5,6,7,8])
>>> numpy.where(x == 0)[0]
array([1, 3, 5])

The method where returns a tuple of ndarrays, each corresponding to a different dimension of the input. Since the input is one-dimensional, the [0] unboxes the tuple's only element.

Josiah Yoder
  • 3,321
  • 4
  • 40
  • 58
mtrw
  • 34,200
  • 7
  • 63
  • 71
  • 22
    I am trying to remember Python. Why does `where()` return a tuple? `numpy.where(x == 0)[1]` is out of bounds. what is the index array coupled to then? – Zhubarb Jan 07 '14 at 12:52
  • @Zhubarb - Most uses of indeces are tuples - `np.zeros((3,))` to make a 3-long vector for instance. I suspect this is to make parsing the params easy. Otherwise something like `np.zeros(3,0,dtype='int16')` versus `np.zeros(3,3,3,dtype='int16')` would be annoying to implement. – mtrw Jan 13 '14 at 10:40
  • 8
    no. `where` returns a tuple of `ndarray`s, each of them corresponding to a dimension of the input. in this case the input is an array, so the output is a `1-tuple`. If x was a matrix, it would be a `2-tuple`, and so on – Ciprian Tomoiagă May 26 '17 at 15:23
  • 5
    As of numpy 1.16, the [documentation for `numpy.where`](https://docs.scipy.org/doc/numpy-1.16.0/reference/generated/numpy.where.html) specifically recommends using `numpy.nonzero` directly rather than calling `where` with only one argument. – jirassimok Jul 18 '19 at 21:54
  • 1
    @jirassimok how do you use nonzero to find zeros as the question asks? – mLstudent33 Apr 17 '20 at 05:39
  • 1
    @mLstudent33 Exactly the same way as you would use `where`, as seen in [Dusch's answer](https://stackoverflow.com/a/24553551). As per [`where`'s documentation](https://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html), `where(x)` is equivalent to `asarray(x).nonzero()`. – jirassimok Apr 17 '20 at 19:37
  • Oh, because an expression like `x==0` returns `[True,False,False...]` and `nonzero()` returns the indies to the `True` values. Very non-intuitive to use `nonzero()` to find zeros! (hence the original question). – Demis Jan 08 '23 at 00:06
57

There is np.argwhere,

import numpy as np
arr = np.array([[1,2,3], [0, 1, 0], [7, 0, 2]])
np.argwhere(arr == 0)

which returns all found indices as rows:

array([[1, 0],    # Indices of the first zero
       [1, 2],    # Indices of the second zero
       [2, 1]],   # Indices of the third zero
      dtype=int64)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MSeifert
  • 145,886
  • 38
  • 333
  • 352
29

You can search for any scalar condition with:

>>> a = np.asarray([0,1,2,3,4])
>>> a == 0 # or whatver
array([ True, False, False, False, False], dtype=bool)

Which will give back the array as an boolean mask of the condition.

nate c
  • 8,802
  • 2
  • 27
  • 28
26

You can also use nonzero() by using it on a boolean mask of the condition, because False is also a kind of zero.

>>> x = numpy.array([1,0,2,0,3,0,4,5,6,7,8])

>>> x==0
array([False, True, False, True, False, True, False, False, False, False, False], dtype=bool)

>>> numpy.nonzero(x==0)[0]
array([1, 3, 5])

It's doing exactly the same as mtrw's way, but it is more related to the question ;)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dusch
  • 420
  • 4
  • 10
  • 2
    This should be the accepted answer as this is the advised use of `nonzero` method to check conditions. – sophros Mar 20 '19 at 09:42
7

You can use numpy.nonzero to find zero.

>>> import numpy as np
>>> x = np.array([1,0,2,0,3,0,0,4,0,5,0,6]).reshape(4, 3)
>>> np.nonzero(x==0)  # this is what you want
(array([0, 1, 1, 2, 2, 3]), array([1, 0, 2, 0, 2, 1]))
>>> np.nonzero(x)
(array([0, 0, 1, 2, 3, 3]), array([0, 2, 1, 1, 0, 2]))
chmnsk
  • 71
  • 1
  • 3
6

If you are working with a one-dimensional array there is a syntactic sugar:

>>> x = numpy.array([1,0,2,0,3,0,4,5,6,7,8])
>>> numpy.flatnonzero(x == 0)
array([1, 3, 5])
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dvdvck
  • 417
  • 4
  • 8
  • This works fine as long as I have only one condition. What if I want to search for "x == numpy.array(0,2,7)"? The result should be array([1,2,3,5,9]). But how can I get this? – MoTSCHIGGE Aug 08 '14 at 11:04
  • You could do this with: `numpy.flatnonzero(numpy.logical_or(numpy.logical_or(x==0, x==2), x==7))` – Dusch Apr 12 '16 at 10:20
3
import numpy as np
arr = np.arange(10000)
arr[8000:8900] = 0

%timeit np.where(arr == 0)[0]
%timeit np.argwhere(arr == 0)
%timeit np.nonzero(arr==0)[0]
%timeit np.flatnonzero(arr==0)
%timeit np.amin(np.extract(arr != 0, arr))
23.4 µs ± 1.5 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
34.5 µs ± 680 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
23.2 µs ± 447 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
27 µs ± 506 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
109 µs ± 669 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Demetry Pascal
  • 383
  • 4
  • 15
2

I would do it the following way:

>>> x = np.array([[1,0,0], [0,2,0], [1,1,0]])
>>> x
array([[1, 0, 0],
       [0, 2, 0],
       [1, 1, 0]])
>>> np.nonzero(x)
(array([0, 1, 2, 2]), array([0, 1, 0, 1]))

# if you want it in coordinates
>>> x[np.nonzero(x)]
array([1, 2, 1, 1])
>>> np.transpose(np.nonzero(x))
array([[0, 0],
       [1, 1],
       [2, 0],
       [2, 1])
Jeril
  • 7,858
  • 3
  • 52
  • 69
1
import numpy as np

x = np.array([1,0,2,3,6])
non_zero_arr = np.extract(x>0,x)

min_index = np.amin(non_zero_arr)
min_value = np.argmin(non_zero_arr)
sramij
  • 4,775
  • 5
  • 33
  • 55