NumPy 数据类型比较

NumPy data type comparison

我正在尝试比较两个不同数组的数据类型,以选择一个适合组合两者的数组。我很高兴地发现我可以执行比较操作,但在这个过程中发现了以下奇怪的行为:

In [1]: numpy.int16 > numpy.float32
Out[1]: True

In [2]: numpy.dtype('int16') > numpy.dtype('float32')
Out[2]: False

谁能解释一下这是怎么回事?这是 NumPy 1.8.2.

没什么意思。 Python 2 尝试为未定义如何相互比较的对象提供一致但无意义的比较结果。开发人员认为这是一个错误,在 Python 3 中,这些比较将引发 TypeError.

第一个比较没有意义,第二个有意义。

对于 numpy.int16 > numpy.float32 我们正在比较两个 type 对象:

>>> type(numpy.int16)
type
>>> numpy.int16 > numpy.float32 # I'm using Python 3
TypeError: unorderable types: type() > type()

在 Python 3 中,此比较立即失败,因为没有为 type 实例定义顺序。在 Python 2 中,返回了一个布尔值,但不能依赖其一致性(它回退到比较内存地址或其他实现级别的东西)。

第二个比较 在 Python 3 中起作用,并且它始终如一地起作用(在 Python 2 中相同)。这是因为我们现在正在比较 dtype 个实例:

>>> type(numpy.dtype('int16'))
numpy.dtype
>>> numpy.dtype('int16') > numpy.dtype('float32')
False
>>> numpy.dtype('int32') < numpy.dtype('|S10')
False
>>> numpy.dtype('int32') < numpy.dtype('|S11')
True

这个顺序背后的逻辑是什么?

dtype 个实例根据一个实例是否可以(安全地)转换为另一个实例来排序。一种类型小于另一种类型,如果它可以安全地转换到那种类型。

比较运算符的实现,参见descriptor.c; specifically at the arraydescr_richcompare函数。

这是 < 运算符映射到的内容:

switch (cmp_op) {
 case Py_LT:
        if (!PyArray_EquivTypes(self, new) && PyArray_CanCastTo(self, new)) {
            result = Py_True;
        }
        else {
            result = Py_False;
        }
        break;

本质上,NumPy 只是检查这两种类型 (i) 不等价,以及 (ii) 第一种类型可以转换为第二种类型。

此功能也在 NumPy API 中公开为 np.can_cast:

>>> np.can_cast('int32', '|S10')
False
>>> np.can_cast('int32', '|S11')
True