【问题标题】:How exactly does the behavior of Python bool and numpy bool_ differ?Python bool 和 numpy bool_ 的行为究竟有何不同?
【发布时间】:2019-09-18 05:10:27
【问题描述】:

TLDR: is-comparison 适用于 Python bool,不适用于 numpy bool_。是否存在其他差异?


几天前我遇到了一个奇怪的布尔值行为。当我尝试对这个 numpy 数组使用 is-comparison 时:

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

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

(这些变量名是虚构的,与真实变量名或生产代码的任何相似之处纯属巧合)

我看到了这个结果:

arr1 is True

Out[...]: False

这是合乎逻辑的,因为arr1 不是 True 或 False,它是 numpy 数组。我检查了这个:

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]

此外,它还在我的另一个 numpy 数组中工作:

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 布尔值,而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 数组是否仅包含 numpy 布尔值,而不包含 Pythonic 布尔值?

(PS:是的,现在我知道用is比较真/假是不好的):

不要使用 == 将布尔值与 True 或 False 进行比较。

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

编辑1:正如another question 中提到的,numpy 有自己的bool_ 类型。但是这个问题的细节有点不同:我发现 is-statements 的工作方式不同,但在这种差异之前 - bool_bool 行为是否有其他共同点?如果是,具体是什么?

【问题讨论】:

标签: python numpy


【解决方案1】:
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)

注意数据类型。使用 object dtype,数组的元素是 Python 对象,就像它们在源列表中一样。

在第一种情况下,数组 dtype 是布尔值。这些元素表示布尔值,但它们本身不是 Python True/False 对象。严格来说 Out[119] 不是 contain np.bool_ 对象。 Out[119][1]bool_ 类型,但这是“拆箱”的结果。这是ndarray 索引在您请求元素时产生的。 (这种“拆箱”区别适用于所有非对象 dtype。)

通常我们不创建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 测试。

让我们玩一下 object 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】:

    变量有一些混淆,发生的是模块和 python 之间的“混淆”,使用isinstance(variable, type) 检查它是什么 if 可用于您的代码。

    将单个变量创建为 bool 变量可以正常工作,python 会正确地使用它:

    np_bool = np.bool(True)
    py_bool = True
    
    print(isinstance(np_bool, bool)) # True
    print(isinstance(py_bool, bool)) # True
    

    但是列表可能会有所不同,numpy 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))
    

    【讨论】:

      【解决方案3】:

      另一个区别是自动转换为整数可以在 np.bool 上完成,但不能在 np.bool_ 上完成。

      这是必需的,例如here

      >>> np.bool(False) - np.bool(True)
      -1
      
      >>> np.bool_(False) - np.bool_(True)
      TypeError: numpy boolean subtract, the `-` operator, is not supported, use the bitwise_xor, the `^` operator, or the logical_xor function instead.
      
      

      【讨论】:

        猜你喜欢
        • 2018-04-24
        • 2021-06-20
        • 1970-01-01
        • 2019-07-21
        • 2011-05-08
        • 2018-12-16
        • 2014-04-30
        • 1970-01-01
        相关资源
        最近更新 更多