具有一个错误元素的 numpy 数组的真值似乎取决于 dtype
Truth value of numpy array with one falsey element seems to depend on dtype
import numpy as np
a = np.array([0])
b = np.array([None])
c = np.array([''])
d = np.array([' '])
为什么我们会有这种不一致:
>>> bool(a)
False
>>> bool(b)
False
>>> bool(c)
True
>>> bool(d)
False
Numpy 似乎遵循与内置 python** 相同的转换,在此上下文中 it seems to be because of which return true for calls to nonzero
。显然 len
也可以使用,但在这里,这些数组中的 none 是空的(长度 0
)——所以这并不直接相关。请注意,根据这些规则调用 bool([False])
也会 returns True
。
a = np.array([0])
b = np.array([None])
c = np.array([''])
>>> nonzero(a)
(array([], dtype=int64),)
>>> nonzero(b)
(array([], dtype=int64),)
>>> nonzero(c)
(array([0]),)
This also seems consistent with the more enumerative description of bool
casting --- 你的例子都被明确讨论了。
有趣的是,字符串数组似乎确实存在系统性不同的行为,例如
>>> a.astype(bool)
array([False], dtype=bool)
>>> b.astype(bool)
array([False], dtype=bool)
>>> c.astype(bool)
ERROR: ValueError: invalid literal for int() with base 10: ''
I think, when numpy converts something into a bool it uses the PyArray_BoolConverter
function 依次调用 PyObject_IsTrue
函数 --- 即内置 python 使用的完全相同的函数,这就是为什么 numpy
'结果是如此一致。
我很确定答案是,正如 Scalars 中所解释的那样:
Array scalars have the same attributes and methods as ndarrays. [1] This allows one to treat items of an array partly on the same footing as arrays, smoothing out rough edges that result when mixing scalar and array operations.
因此,如果在标量上调用 bool
是可以接受的,那么在形状为 (1,)
的数组上调用 bool
也必须是可以接受的,因为它们是,至于可能,同样的事情。
而且,虽然在我所知道的文档中的任何地方都没有直接说明,但从设计中可以明显看出 NumPy 的标量应该像本机 Python 对象一样工作。
所以,这就解释了为什么 np.array([0])
是虚假的而不是真实的,这正是您最初感到惊讶的地方。
所以,这解释了基础知识。但是案例 c
的具体情况呢?
首先,请注意您的数组 np.array([''])
不是一个 Python object
的数组,而是一个 NumPy <U1
空终止字符串的数组length 1. 固定长度的字符串值不具有与 Python 字符串相同的真实性规则——它们确实不能;对于固定长度的字符串类型,"false if empty" 没有任何意义,因为它们 从不 为空。您可能会争论 NumPy 是否应该以这种方式设计,但它显然始终如一地遵循该规则,而且我认为相反的规则在这里不会减少混淆,只是有所不同。
但是字符串似乎还有其他奇怪的事情发生。考虑一下:
>>> np.array(['a', 'b']) != 0
True
这不是将 <U2
字符串与 0 和 returning array([True, True])
进行元素比较(正如您从 np.array(['a', 'b'], dtype=object)
得到的那样),它是在做一个数组范围的比较并决定没有字符串数组等于 0,这看起来很奇怪……我不确定这是否值得在这里单独回答,甚至是一个完整的单独问题,但我很确定我不会是写那个答案的人,因为我不知道这里发生了什么。 :)
除了形状为 (1,)
的数组之外,形状为 ()
的数组也以同样的方式处理,但其他任何东西都是 ValueError
,否则很容易误用数组使用 and
和其他 Python 运算符,NumPy 无法自动将其转换为逐元素运算。
我个人认为与其他数组保持一致比在这里与标量保持一致更有用——换句话说,只需提出一个 ValueError
。我还认为,如果与标量一致 在这里很重要 ,那么与未装箱的 Python 值保持一致会更好。换句话说,如果完全允许 bool(array([v]))
和 bool(array(v))
,它们应该始终 return 与 bool(v)
完全相同,即使这与 np.nonzero
。但我可以从另一个角度看待这个论点。
对于只有一个元素的数组,数组的真值由该元素的真值决定。
要说明的要点是 np.array([''])
是 而不是 包含一个空 Python 字符串的数组。创建此数组是为了保存每个字符串恰好为一个字节,NumPy 会用空字符填充太短的字符串。这意味着数组等于 np.array(['[=15=]'])
.
在这方面,NumPy 与 Python 一致,后者将 bool('[=16=]')
计算为 True
。
事实上,NumPy 数组中唯一 False
的字符串是不包含任何非空白字符的字符串('[=19=]'
不是空白字符)。
此布尔计算的详细信息如下所示。
浏览 NumPy 的迷宫式源代码并不总是那么容易,但我们可以在 arraytypes.c.src 文件中找到管理不同数据类型中的值如何映射到布尔值的代码。这将解释如何确定 bool(a)
、bool(b)
、bool(c)
和 bool(d)
。
在查看该文件中的代码之前,我们可以看到在 NumPy 数组上调用 bool()
会调用内部 _array_nonzero()
函数。如果数组为空,我们得到 False
。如果有两个或更多元素,我们会得到一个错误。但是如果数组有 正好 个元素,我们就命中了这一行:
return PyArray_DESCR(mp)->f->nonzero(PyArray_DATA(mp), mp);
现在,PyArray_DESCR
is a struct holding various properties for the array. f
is a pointer to another struct PyArray_ArrFuncs
包含数组的 nonzero
函数。换句话说,NumPy 将调用数组自己的特殊 nonzero
函数来检查该元素的布尔值。
确定一个元素是否非零显然取决于元素的数据类型。实现特定类型非零函数的代码可以在 arraytypes.c.src 文件的 "nonzero" 部分找到。
如我们所料,如果浮点数、整数和复数是 equal with zero. This explains bool(a)
. In the case of object arrays, None
is similarly going to be evaluated as False
because NumPy just calls the PyObject_IsTrue
function,则它们是 False
。这解释了 bool(b)
.
为了理解bool(c)
和bool(d)
的结果,我们看到字符串类型数组的nonzero
函数映射到STRING_nonzero
函数:
static npy_bool
STRING_nonzero (char *ip, PyArrayObject *ap)
{
int len = PyArray_DESCR(ap)->elsize; // size of dtype (not string length)
int i;
npy_bool nonz = NPY_FALSE;
for (i = 0; i < len; i++) {
if (!Py_STRING_ISSPACE(*ip)) { // if it isn't whitespace, it's True
nonz = NPY_TRUE;
break;
}
ip++;
}
return nonz;
}
(unicode 大小写大致相同。)
因此在具有字符串或 unicode 数据类型的数组中,如果字符串仅包含空白字符,则它只是 False
:
>>> bool(np.array([' ']))
False
在问题中数组 c
的情况下,确实有一个空字符 [=44=]
填充看似空的字符串:
>>> np.array(['']) == np.array(['[=13=]'])
array([ True], dtype=bool)
STRING_nonzero
函数看到这个非空白字符,所以 bool(c)
是 True
。
如本答案开头所述,这与 Python 对包含单个空字符的字符串的评估一致:bool('[=16=]')
也是 True
.
Update: 上面在 NumPy 的 master 分支中详细介绍了通过制作仅包含空字符或仅包含空白和空字符的字符串,评估为 False
。这意味着 NumPy 1.10+ 将看到 bool(np.array(['']))
是 False
,这更符合 Python 对 "empty" 字符串的处理。
现在 fixed in master。
我认为这是一个错误,numpy
开发人员也同意,所以今天早些时候 patch was merged。我们应该会在即将发布的 1.10 版本中看到新的行为。
import numpy as np
a = np.array([0])
b = np.array([None])
c = np.array([''])
d = np.array([' '])
为什么我们会有这种不一致:
>>> bool(a)
False
>>> bool(b)
False
>>> bool(c)
True
>>> bool(d)
False
Numpy 似乎遵循与内置 python** 相同的转换,在此上下文中 it seems to be because of which return true for calls to nonzero
。显然 len
也可以使用,但在这里,这些数组中的 none 是空的(长度 0
)——所以这并不直接相关。请注意,根据这些规则调用 bool([False])
也会 returns True
。
a = np.array([0])
b = np.array([None])
c = np.array([''])
>>> nonzero(a)
(array([], dtype=int64),)
>>> nonzero(b)
(array([], dtype=int64),)
>>> nonzero(c)
(array([0]),)
This also seems consistent with the more enumerative description of bool
casting --- 你的例子都被明确讨论了。
有趣的是,字符串数组似乎确实存在系统性不同的行为,例如
>>> a.astype(bool)
array([False], dtype=bool)
>>> b.astype(bool)
array([False], dtype=bool)
>>> c.astype(bool)
ERROR: ValueError: invalid literal for int() with base 10: ''
I think, when numpy converts something into a bool it uses the PyArray_BoolConverter
function 依次调用 PyObject_IsTrue
函数 --- 即内置 python 使用的完全相同的函数,这就是为什么 numpy
'结果是如此一致。
我很确定答案是,正如 Scalars 中所解释的那样:
Array scalars have the same attributes and methods as ndarrays. [1] This allows one to treat items of an array partly on the same footing as arrays, smoothing out rough edges that result when mixing scalar and array operations.
因此,如果在标量上调用 bool
是可以接受的,那么在形状为 (1,)
的数组上调用 bool
也必须是可以接受的,因为它们是,至于可能,同样的事情。
而且,虽然在我所知道的文档中的任何地方都没有直接说明,但从设计中可以明显看出 NumPy 的标量应该像本机 Python 对象一样工作。
所以,这就解释了为什么 np.array([0])
是虚假的而不是真实的,这正是您最初感到惊讶的地方。
所以,这解释了基础知识。但是案例 c
的具体情况呢?
首先,请注意您的数组 np.array([''])
不是一个 Python object
的数组,而是一个 NumPy <U1
空终止字符串的数组length 1. 固定长度的字符串值不具有与 Python 字符串相同的真实性规则——它们确实不能;对于固定长度的字符串类型,"false if empty" 没有任何意义,因为它们 从不 为空。您可能会争论 NumPy 是否应该以这种方式设计,但它显然始终如一地遵循该规则,而且我认为相反的规则在这里不会减少混淆,只是有所不同。
但是字符串似乎还有其他奇怪的事情发生。考虑一下:
>>> np.array(['a', 'b']) != 0
True
这不是将 <U2
字符串与 0 和 returning array([True, True])
进行元素比较(正如您从 np.array(['a', 'b'], dtype=object)
得到的那样),它是在做一个数组范围的比较并决定没有字符串数组等于 0,这看起来很奇怪……我不确定这是否值得在这里单独回答,甚至是一个完整的单独问题,但我很确定我不会是写那个答案的人,因为我不知道这里发生了什么。 :)
除了形状为 (1,)
的数组之外,形状为 ()
的数组也以同样的方式处理,但其他任何东西都是 ValueError
,否则很容易误用数组使用 and
和其他 Python 运算符,NumPy 无法自动将其转换为逐元素运算。
我个人认为与其他数组保持一致比在这里与标量保持一致更有用——换句话说,只需提出一个 ValueError
。我还认为,如果与标量一致 在这里很重要 ,那么与未装箱的 Python 值保持一致会更好。换句话说,如果完全允许 bool(array([v]))
和 bool(array(v))
,它们应该始终 return 与 bool(v)
完全相同,即使这与 np.nonzero
。但我可以从另一个角度看待这个论点。
对于只有一个元素的数组,数组的真值由该元素的真值决定。
要说明的要点是 np.array([''])
是 而不是 包含一个空 Python 字符串的数组。创建此数组是为了保存每个字符串恰好为一个字节,NumPy 会用空字符填充太短的字符串。这意味着数组等于 np.array(['[=15=]'])
.
在这方面,NumPy 与 Python 一致,后者将 bool('[=16=]')
计算为 True
。
事实上,NumPy 数组中唯一 False
的字符串是不包含任何非空白字符的字符串('[=19=]'
不是空白字符)。
此布尔计算的详细信息如下所示。
浏览 NumPy 的迷宫式源代码并不总是那么容易,但我们可以在 arraytypes.c.src 文件中找到管理不同数据类型中的值如何映射到布尔值的代码。这将解释如何确定 bool(a)
、bool(b)
、bool(c)
和 bool(d)
。
在查看该文件中的代码之前,我们可以看到在 NumPy 数组上调用 bool()
会调用内部 _array_nonzero()
函数。如果数组为空,我们得到 False
。如果有两个或更多元素,我们会得到一个错误。但是如果数组有 正好 个元素,我们就命中了这一行:
return PyArray_DESCR(mp)->f->nonzero(PyArray_DATA(mp), mp);
现在,PyArray_DESCR
is a struct holding various properties for the array. f
is a pointer to another struct PyArray_ArrFuncs
包含数组的 nonzero
函数。换句话说,NumPy 将调用数组自己的特殊 nonzero
函数来检查该元素的布尔值。
确定一个元素是否非零显然取决于元素的数据类型。实现特定类型非零函数的代码可以在 arraytypes.c.src 文件的 "nonzero" 部分找到。
如我们所料,如果浮点数、整数和复数是 equal with zero. This explains bool(a)
. In the case of object arrays, None
is similarly going to be evaluated as False
because NumPy just calls the PyObject_IsTrue
function,则它们是 False
。这解释了 bool(b)
.
为了理解bool(c)
和bool(d)
的结果,我们看到字符串类型数组的nonzero
函数映射到STRING_nonzero
函数:
static npy_bool
STRING_nonzero (char *ip, PyArrayObject *ap)
{
int len = PyArray_DESCR(ap)->elsize; // size of dtype (not string length)
int i;
npy_bool nonz = NPY_FALSE;
for (i = 0; i < len; i++) {
if (!Py_STRING_ISSPACE(*ip)) { // if it isn't whitespace, it's True
nonz = NPY_TRUE;
break;
}
ip++;
}
return nonz;
}
(unicode 大小写大致相同。)
因此在具有字符串或 unicode 数据类型的数组中,如果字符串仅包含空白字符,则它只是 False
:
>>> bool(np.array([' ']))
False
在问题中数组 c
的情况下,确实有一个空字符 [=44=]
填充看似空的字符串:
>>> np.array(['']) == np.array(['[=13=]'])
array([ True], dtype=bool)
STRING_nonzero
函数看到这个非空白字符,所以 bool(c)
是 True
。
如本答案开头所述,这与 Python 对包含单个空字符的字符串的评估一致:bool('[=16=]')
也是 True
.
Update: False
。这意味着 NumPy 1.10+ 将看到 bool(np.array(['']))
是 False
,这更符合 Python 对 "empty" 字符串的处理。
现在 fixed in master。
我认为这是一个错误,numpy
开发人员也同意,所以今天早些时候 patch was merged。我们应该会在即将发布的 1.10 版本中看到新的行为。