Проверить, содержит ли массив numpy только нули

93

Мы инициализируем массив numpy нулями, как показано ниже:

np.zeros((N,N+1))

Но как проверить, все ли элементы в заданной матрице массива n * n numpy равны нулю.
Метод просто должен вернуть True, если все значения действительно равны нулю.

IНеизвестно
источник

Ответы:

73

Проверьте numpy.count_nonzero .

>>> np.count_nonzero(np.eye(4))
4
>>> np.count_nonzero([[0,1,7,0,0],[3,0,0,2,19]])
5
Прашант Кумар
источник
9
Вы захотите not np.count_nonzero(np.eye(4))вернуться, Trueтолько если все значения равны 0.
Ж. Мартинот-Лагард
166

Другие ответы, размещенные здесь, будут работать, но наиболее четкая и эффективная функция для использования numpy.any():

>>> all_zeros = not np.any(a)

или

>>> all_zeros = not a.any()
  • Это предпочтительнее, numpy.all(a==0)потому что он использует меньше оперативной памяти. (Это не требует временного массива, созданного a==0термином.)
  • Кроме того, это быстрее, чем numpy.count_nonzero(a)потому, что он может немедленно вернуться, когда будет найден первый ненулевой элемент.
    • Изменить: как @Rachel указал в комментариях, np.any()больше не использует логику «короткого замыкания», поэтому вы не увидите увеличения скорости для небольших массивов.
Стюарт Берг
источник
3
На минуте назад, NumPy - х anyи allделать не короткое замыкание. Я считаю, что они сахар logical_or.reduceи logical_and.reduce. Сравните друг с другом и с моим коротким замыканием is_in: all_false = np.zeros(10**8) all_true = np.ones(10**8) %timeit np.any(all_false) 91.5 ms ± 1.82 ms per loop %timeit np.any(all_true) 93.7 ms ± 6.16 ms per loop %timeit is_in(1, all_true) 293 ns ± 1.65 ns per loop
Рэйчел
3
Отличный момент, спасибо. Похоже, раньше было короткое замыкание , но в какой-то момент оно было потеряно. В ответах на этот вопрос есть интересное обсуждение .
Стюарт Берг
50

Я бы использовал здесь np.all, если у вас есть массив a:

>>> np.all(a==0)
Ж. Мартино-Лагард
источник
3
Мне нравится, что этот ответ также проверяет ненулевые значения. Например, можно проверить, все ли элементы в массиве одинаковы, выполнив следующие действия np.all(a==a[0]). Большое спасибо!
aignas
9

Как говорится в другом ответе, вы можете воспользоваться оценками правдивости / ложности, если вы знаете, что 0это единственный ложный элемент, возможно, в вашем массиве. Все элементы в массиве являются ложными, если в нем нет никаких правдивых элементов. *

>>> a = np.zeros(10)
>>> not np.any(a)
True

Однако ответ утверждал, что anyэто быстрее, чем другие варианты, частично из-за короткого замыкания. По состоянию на 2018 год, Numpy's allи any не замыкаются .

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

import numba as nb

# short-circuiting replacement for np.any()
@nb.jit(nopython=True)
def sc_any(array):
    for x in array.flat:
        if x:
            return True
    return False

# short-circuiting replacement for np.all()
@nb.jit(nopython=True)
def sc_all(array):
    for x in array.flat:
        if not x:
            return False
    return True

Они, как правило, быстрее, чем версии Numpy, даже без короткого замыкания. count_nonzeroсамый медленный.

Некоторые данные для проверки производительности:

import numpy as np

n = 10**8
middle = n//2
all_0 = np.zeros(n, dtype=int)
all_1 = np.ones(n, dtype=int)
mid_0 = np.ones(n, dtype=int)
mid_1 = np.zeros(n, dtype=int)
np.put(mid_0, middle, 0)
np.put(mid_1, middle, 1)
# mid_0 = [1 1 1 ... 1 0 1 ... 1 1 1]
# mid_1 = [0 0 0 ... 0 1 0 ... 0 0 0]

Проверьте:

## count_nonzero
%timeit np.count_nonzero(all_0) 
# 220 ms ± 8.73 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit np.count_nonzero(all_1)
# 150 ms ± 4.56 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

### all
# np.all
%timeit np.all(all_1)
%timeit np.all(mid_0)
%timeit np.all(all_0)
# 56.8 ms ± 3.41 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 57.4 ms ± 1.76 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 55.9 ms ± 2.13 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

# sc_all
%timeit sc_all(all_1)
%timeit sc_all(mid_0)
%timeit sc_all(all_0)
# 44.4 ms ± 2.49 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 22.7 ms ± 599 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 288 ns ± 6.36 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

### any
# np.any
%timeit np.any(all_0)
%timeit np.any(mid_1)
%timeit np.any(all_1)
# 60.7 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 60 ms ± 287 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 57.7 ms ± 1.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

# sc_any
%timeit sc_any(all_0)
%timeit sc_any(mid_1)
%timeit sc_any(all_1)
# 41.7 ms ± 1.24 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 22.4 ms ± 1.51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 287 ns ± 12.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

* Полезные allи anyэквиваленты:

np.all(a) == np.logical_not(np.any(np.logical_not(a)))
np.any(a) == np.logical_not(np.all(np.logical_not(a)))
not np.all(a) == np.any(np.logical_not(a))
not np.any(a) == np.all(np.logical_not(a))
Рэйчел
источник
-8

Если вы тестируете все нули, чтобы избежать предупреждения о другой функции numpy, тогда перенос строки в try, except block избавит вас от необходимости выполнять тест на нули перед операцией, которая вас интересует, т.е.

try: # removes output noise for empty slice 
    mean = np.mean(array)
except:
    mean = 0
ReaddyEddy
источник