Логические операции, булевые маски

Сравнение массивов NumPy

Операторы сравнения <, <=, >, >=, == и != перегружены для массивов numpy и работают аналогичные правила, как и для арифметических операторов:

  • выполняется поэлементное сравнение;

  • формы должны или совпадать или быть совместимы (broadcastable).

Результатом операции сравнения является ndarray наиболее общей формы, содержащий булевые значения True и False.

import numpy as np


A = np.arange(16).reshape(4, 4)
print(A)
print(A >= 7)
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]
[[False False False False]
 [False False False  True]
 [ True  True  True  True]
 [ True  True  True  True]]

В отличие от встроенных в python булевых значений, логические операции “И”, “ИЛИ” и “НЕ” (логическое отрицание) осуществляются операторами |, & и ~, а не ключевыми словами and, or и not.

Note

В самом python операторы |, & и ~ определенны для целых чисел и представляют из себя побитовые операции.

Логическое “И”:

(A > 4) & (A < 11) 
array([[False, False, False, False],
       [False,  True,  True,  True],
       [ True,  True,  True, False],
       [False, False, False, False]])

Логическое “ИЛИ”:

(A < 4) | (A > 11) 
array([[ True,  True,  True,  True],
       [False, False, False, False],
       [False, False, False, False],
       [ True,  True,  True,  True]])

Логическое отрицание:

mask = A > 7
print(mask)
print(~mask)
[[False False False False]
 [False False False False]
 [ True  True  True  True]
 [ True  True  True  True]]
[[ True  True  True  True]
 [ True  True  True  True]
 [False False False False]
 [False False False False]]

Индексация булевымы массивами

Такая булевые массивы могут быть использованы для индексации. Это часто используется для фильтрации значений и т.п.

print(A[A > 7])
[ 8  9 10 11 12 13 14 15]
print(A[(A<3) | (A>7)])
[ 0  1  2  8  9 10 11 12 13 14 15]

При этом допускается даже присваивание.

A[A > 7] = 0
print(A)
[[0 1 2 3]
 [4 5 6 7]
 [0 0 0 0]
 [0 0 0 0]]

Можно индексировать булевыми масками вдоль осей. Например, оставить только строки, напротив которых стоит True.

a1dmask = np.array([True, True, False, True])
A[a1dmask]
array([[0, 1, 2, 3],
       [4, 5, 6, 7],
       [0, 0, 0, 0]])

Или аналогично со столбцами.

A[:, a1dmask]
array([[0, 1, 3],
       [4, 5, 7],
       [0, 0, 0],
       [0, 0, 0]])

np.any и np.all

Функции np.any и np.all принимают на вход булевый массив и агрегируют значения в нем:

  • np.any возвращает True, если хотя бы один из элементов массива True или приводится к True;

  • np.all возвращает True, если все элементы массива True или приводятся к True.

По поведению эти функции похожи на функции на функции np.sum и np.prod. Они также принимают опциональный аргумент axis.

print(mask)
print(f"any: {np.any(mask)}")
print(f"all: {np.all(mask)}")
[[False False False False]
 [False False False False]
 [ True  True  True  True]
 [ True  True  True  True]]
any: True
all: False
np.all(mask, axis=1)
array([False, False,  True,  True])