Чем именно отличается поведение Python bool и numpy bool_? - PullRequest
0 голосов
/ 29 апреля 2019

TLDR: is-сравнение работает с Python bool и не работает с numpy bool_.Существуют ли какие-то другие различия?


Я столкнулся со странным поведением логических выражений пару дней назад.Когда я пытался использовать is-сравнение для этого массива:

arr1 = np.array([1,0,2,0], dtype=bool)
arr1

Out[...]: array([ True, False,  True, False])

(Эти имена переменных основаны на вымысле, и любое сходство с реальными именами переменных или производственным кодом является чисто случайным)

Я видел этот результат:

arr1 is True

Out[...]: False

Это было логично, потому что arr1 не является Истиной или Ложью, это - массив значений.Я проверил это:

arr1 == True

Out[...]: array([ True, False,  True, False])

Это сработало, как и ожидалось.Я упомянул это милое поведение и сразу же забыл его.На следующий день я проверил истинность элементов массива:

[elem is False for elem in arr1]

и он мне это возвращает!

Out[...]: [False, False, False, False]

Я былдействительно запутался, потому что я вспомнил, что в массивах Python (я думал, что проблема в поведении массивов):

arr2 = [True, False, True, False]
[elem is False for elem in arr2]

это работает:

Out[...]: [False, True, False, True]

Более того,он работал в моем другом массиве:

very_cunning_arr = np.array([1, False, 2, False, []])
[elem is False for elem in very_cunning_arr]

Out[...]: [False, True, False, True, False]

Когда я погрузился в свой массив, я обнаружил, что very_cunning_arr был построен numpy.object из-за парынечисловые элементы, поэтому он содержит Python bools и arr1 был построен как numpy.bool_.Поэтому я проверил их поведение:

numpy_waka = np.bool_(True)
numpy_waka

Out[...]: True

python_waka = True
python_waka

Out[...]: True

[numpy_waka is True, python_waka is True]

И я наконец нашелразница:

Out[...]: [False, True]

После всего этого у меня есть два вопроса:

  1. У numpy.bool_ и bool есть некоторые другие различия в их общихповедение?(Я знаю, что numpy.bool_ имеет много функций и параметров numpy, например, .T и других)
  2. Как проверить, содержит ли массив numpy только numy booleans, без Pythonic bools?

(PS: Да, СЕЙЧАС Я знаю, что сравнивать с True / False с is плохо):

Не сравнивать логические значения с True или Falseиспользуя ==.

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:

Edit 1: Как уже упоминалось в другой вопрос , numpy имеет свой собственный тип bool_.Но детали этого вопроса немного отличаются: я обнаружил, что операторы is работают по-разному, но до этого различия - есть ли что-то другое в обычном поведении bool_ и bool?Если да, то что именно?

Ответы [ 2 ]

2 голосов
/ 29 апреля 2019
In [119]: np.array([1,0,2,0],dtype=bool)                                             
Out[119]: array([ True, False,  True, False])

In [120]: np.array([1, False, 2, False, []])                                         
Out[120]: array([1, False, 2, False, list([])], dtype=object)

Обратите внимание на dtype. При использовании объекта dtype элементы массива являются объектами Python, как и в списке источников.

В первом случае массив dtype является логическим. Элементы представляют логические значения, но сами по себе они не являются объектами Python True/False. Строго говоря, Out[119] не contain np.bool_ объектов. Out[119][1] имеет тип bool_, но это результат «распаковки». Это то, что производит индексирование ndarray, когда вы запрашиваете элемент. (Это различие «распаковки» верно для всех необъектных dtypes.)

Обычно мы не создаем dtype объекты, предпочитая np.array(True), но следуем вашему примеру:

In [124]: np.bool_(True)                                                             
Out[124]: True
In [125]: type(np.bool_(True))                                                       
Out[125]: numpy.bool_
In [126]: np.bool_(True) is True                                                     
Out[126]: False
In [127]: type(True)                                                                 
Out[127]: bool

is - это строгий тест не только на равенство, но и на идентичность. Объекты разных классов не удовлетворяют критерию is. Объекты могут удовлетворять критерию ==, не удовлетворяя критерию is.

Давайте поиграем с массивом dtype объекта:

In [129]: np.array([1, False, 2, np.bool_(False), []])                               
Out[129]: array([1, False, 2, False, list([])], dtype=object)
In [130]: [i is False for i in _]                                                    
Out[130]: [False, True, False, False, False]

На экране Out[129] два объекта False отображаются одинаково, но тест Out[130] показывает, что они разные.


Чтобы сосредоточиться на ваших вопросах.

  • np.bool_(False) - уникальный объект, но отличный от False. Как вы заметили, он имеет много тех же атрибутов / методов, что и np.array(False).

  • Если массив dtype равен bool, он не содержит объектов Python bool. Он даже не содержит np.bool_ объектов. Однако индексация такого массива даст bool_. И применение item() к этому в свою очередь производит Python bool.

  • Если объект массива dtype, он, скорее всего, будет содержать Python bool, если вы не предприняли специальных шагов для включения bool_ объектов.

2 голосов
/ 29 апреля 2019

Существует некоторая путаница с переменными, то, что происходит, является "путаницей" между модулем и питоном, используйте isinstance(variable, type), чтобы проверить, что это, если можно использовать в вашем коде.

Созданиеодиночная переменная как переменная bool работает просто отлично, python корректно отображает ее:

np_bool = np.bool(True)
py_bool = True

print(isinstance(np_bool, bool)) # True
print(isinstance(py_bool, bool)) # True

Но со списками она может быть другой, списки с пустыми значениями bool не являются значениями bool в списке, как вы можете видеть в этом примере:

# Regular list of int
arr0 = [-2, -1, 0, 1, 2]

# Python list of bool
arr1 = [True, False, True, False]

# Numpy list of bool, from int / bool
arr3_a = np.array([-2, -1, 0, 1, 2], dtype=bool)
arr3_b = np.array([True, False, True, False], dtype=bool)

print(isinstance(arr0[0], int))    # True
print(isinstance(arr1[0], bool))   # True

print(isinstance(arr3_a[0], bool)) # False
print(isinstance(arr3_b[0], bool)) # False

Чтобы использовать переменную из списка NumPy требуется преобразование с bool()

arr3_a = np.array([-2, -1, 0, 1, 2], dtype=bool)

x = (bool(arr3_a[0]) is True)
print(isinstance(x, bool)) # True

Быстрый пример использования:

arr3_a = np.array([-2, -1, 0, 1, 2], dtype=bool)

for c in range(0, len(arr3_a)):
    if ( bool(arr3_a[c]) == True ):
        print(("List value {} is True").format(c))
    else:
        print(("List value {} is False").format(c))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...