Сравнение типов данных NumPy
Я играл с сопоставлением типов данных двух разных массивов, чтобы выбрать тот, который подходит для объединения двух. Я был рад узнать, что я мог выполнять операции сравнения, но в процессе обнаружил следующее странное поведение:
In [1]: numpy.int16 > numpy.float32
Out[1]: True
In [2]: numpy.dtype('int16') > numpy.dtype('float32')
Out[2]: False
Может ли кто-нибудь объяснить, что здесь происходит? Это NumPy 1.8.2.
Первое сравнение не имеет смысла, второе имеет смысл.
С 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; особенно в функции 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) что первый тип может быть передан второму типу.
Эта функциональность также отображается в API NumPy как np.can_cast
:
>>> np.can_cast('int32', '|S10')
False
>>> np.can_cast('int32', '|S11')
True
Ничего интересного. Python 2 пытается обеспечить последовательные, но бессмысленные результаты сравнения для объектов, которые не определяют, как сравнивать себя друг с другом. Разработчики решили, что это была ошибка, и в Python 3, эти сравнения повысят TypeError
.