numpy.nonzero
numpy.nonzero(a)
Функция nonzero() возвращает индексы ненулевых элементов массива.
Результат представляет собой кортеж массивов, каждый такой массив соответствует отдельной оси исходного массива и содержит индексы с ненулевыми элементами в этом массиве. Значения проверяются всегда в строковом C-стиле, так что будьте внимательны, если вдруг, вы с того не с сего, начали работать с массивами в стиле Fortran.
-
- a - массив NumPy или подобный массиву объект.
- Исходный массив.
-
- tuple - кортеж Python
- кортеж с массивами индесов ненулевых элементов исходного массива a.
Замечание
Данная функция обладает эквивалентным методом класса 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])