numpy.nonzero

numpy.nonzero(a)

Функция nonzero() возвращает индексы ненулевых элементов массива.

Результат представляет собой кортеж массивов, каждый такой массив соответствует отдельной оси исходного массива и содержит индексы с ненулевыми элементами в этом массиве. Значения проверяются всегда в строковом C-стиле, так что будьте внимательны, если вдруг, вы с того не с сего, начали работать с массивами в стиле Fortran.

Параметры:
a - массив NumPy или подобный массиву объект.
Исходный массив.
Возвращает:
tuple - кортеж Python
кортеж с массивами индесов ненулевых элементов исходного массива a.
Смотрите так же:
flatnonzero, argwhere, count_nonzero

Замечание

Данная функция обладает эквивалентным методом класса ndarray, т.е. np.nonzero(a) равносильно вызову метода a.nonzero():

>>> import numpy as np
>>> 
>>> 
>>> a = np.random.randint(0, 2, 5)
>>> a
array([1, 0, 1, 0, 0])
>>> 
>>> np.nonzero(a)
(array([0, 2], dtype=int32),)
>>> 
>>> a.nonzero()
(array([0, 2], dtype=int32),)


Примеры

Данная функция всегда возвращает кортеж:

>>> import numpy as np
>>> 
>>> a = np.array([[1, 0, 2], [3, 0, 0], [4, 0, 5]])
>>> a
array([[1, 0, 2],
       [3, 0, 0],
       [4, 0, 5]])
>>> 
>>> non_zero_a = np.nonzero(a)
>>> non_zero_a
(array([0, 0, 1, 2, 2], dtype=int32), array([0, 2, 0, 0, 2], dtype=int32))

Каждый массив в этом кортеже, содержит индексы ненулевых элементов для соответствующего измерения, для примера выше, как нетрудно догадаться, первый массив - это индексы строк, второй - столбцов. Для массивов большей размерности, дело обстоит точно так же - один массив индексов для одного измерения.

Для того что бы вытащить ненулевые элементы, достаточно указать результат в качестве индексного выражения:

>>> a[non_zero_a]
array([1, 2, 3, 4, 5])

Иногда нужно сгрупприровать индексы ненулевых индексов не по осям массива, а как набор координат точек, для этого достаточно соединить соответствующие элементы на осях. Для подойдет как объект c_:

>>> np.c_[non_zero_a]
array([[0, 0],
       [0, 2],
       [1, 0],
       [2, 0],
       [2, 2]], dtype=int32)

Так и объект transpose()

>>> np.transpose(non_zero_a)
array([[0, 0],
       [0, 2],
       [1, 0],
       [2, 0],
       [2, 2]], dtype=int32)

Может показаться, что c_ не сработает для массивов с разными размерами осей, но на самом деле, все массивы индексов в возвращаемом кортежи имеют одинаковую длину, поэтому все и работает. Давайте проверим на массиве большей размерности и разной длиной осей:

>>> b = np.random.randint(0, 2, (2, 3, 4))
>>> 
>>> non_zero_b = np.nonzero(b)
>>> non_zero_b
(array([0, 0, 0, ..., 1, 1, 1], dtype=int32),
 array([0, 1, 1, ..., 1, 1, 2], dtype=int32),
 array([3, 1, 2, ..., 2, 3, 3], dtype=int32))
>>> 
>>> np.c_[non_zero_b]
array([[0, 0, 3],
       [0, 1, 1],
       [0, 1, 2],
       ...,
       [1, 1, 2],
       [1, 1, 3],
       [1, 2, 3]], dtype=int32)
>>> 
>>> np.transpose(non_zero_b)
array([[0, 0, 3],
       [0, 1, 1],
       [0, 1, 2],
       ...,
       [1, 1, 2],
       [1, 1, 3],
       [1, 2, 3]], dtype=int32)
>>> 
>>> np.c_[non_zero_b] == np.transpose(non_zero_b)
array([[ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True],
       ...,
       [ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True]])

Кстати, логические True и False на самом деле являются кдиницей и нулем соответственно, а это значит, что мы можем применять nonzero() к результатам логических операций над массивами. Например:

>>> a
array([[1, 0, 2],
       [3, 0, 0],
       [4, 0, 5]])
>>> 
>>> c = a > 3
>>> c
array([[False, False, False],
       [False, False, False],
       [ True, False,  True]])
>>> 
>>> np.nonzero(c)
(array([2, 2], dtype=int32), array([0, 2], dtype=int32))
>>> 
>>> c[np.nonzero(c)]
array([ True,  True])

Что, может быть использовано для преобразования булевых массивов индексов в массивы индексов с целыми числами:

>>> a[c]    #  индексация массивом булевых значений
array([4, 5])
>>> 
>>> a[np.nonzero(c)]    #  индексация массивами целых чисел
array([4, 5])