Идентификация числовых типов и массивов в numpy

StackOverflow https://stackoverflow.com/questions/500328

  •  20-08-2019
  •  | 
  •  

Вопрос

Есть ли существующая функция в numpy, которая сообщит мне, является ли значение либо числовым типом, либо массивом numpy?Я пишу некоторый код обработки данных, который должен обрабатывать числа в нескольких различных представлениях (под "числом" я подразумеваю любое представление числовой величины, которым можно манипулировать с помощью стандартных арифметических операторов, +, -, *, /, **).

Несколько примеров поведения, которое я ищу

>>> is_numeric(5)
True
>>> is_numeric(123.345)
True
>>> is_numeric('123.345')
False
>>> is_numeric(decimal.Decimal('123.345'))
True
>>> is_numeric(True)
False
>>> is_numeric([1, 2, 3])
False
>>> is_numeric([1, '2', 3])
False
>>> a = numpy.array([1, 2.3, 4.5, 6.7, 8.9])
>>> is_numeric(a)
True
>>> is_numeric(a[0])
True
>>> is_numeric(a[1])
True
>>> is_numeric(numpy.array([numpy.array([1]), numpy.array([2])])
True
>>> is_numeric(numpy.array(['1'])
False

Если такой функции не существует, я знаю, что написать ее не составит труда, что-то вроде

isinstance(n, (int, float, decimal.Decimal, numpy.number, numpy.ndarray))

но есть ли другие числовые типы, которые я должен включить в список?

Это было полезно?

Решение

Как уже отвечали другие, могут существовать и другие числовые типы, помимо тех, которые вы упомянули.Одним из подходов было бы явно проверить наличие нужных вам возможностей с помощью чего-то вроде

# Python 2
def is_numeric(obj):
    attrs = ['__add__', '__sub__', '__mul__', '__div__', '__pow__']
    return all(hasattr(obj, attr) for attr in attrs)

# Python 3
def is_numeric(obj):
    attrs = ['__add__', '__sub__', '__mul__', '__truediv__', '__pow__']
    return all(hasattr(obj, attr) for attr in attrs)

Это работает для всех ваших примеров, кроме последнего, numpy.array(['1']).Это потому, что numpy.ndarray имеет специальные методы для числовых операций, но вызывает TypeError, если вы пытаетесь использовать их ненадлежащим образом со строковыми или объектными массивами.Вы могли бы добавить явную проверку для этого, например

 ... and not (isinstance(obj, ndarray) and obj.dtype.kind in 'OSU')

Этого может быть достаточно.

Но...ты никогда не сможешь быть 100% уверен, что кто-нибудь не определит другой тип с таким же поведением, поэтому более надежный способ - на самом деле попытаться выполнить вычисление и перехватить исключение, что-то вроде

def is_numeric_paranoid(obj):
    try:
        obj+obj, obj-obj, obj*obj, obj**obj, obj/obj
    except ZeroDivisionError:
        return True
    except Exception:
        return False
    else:
        return True

но в зависимости от того, как часто вы планируете вызывать use it и с какими аргументами, это может быть непрактично (это может быть потенциально медленно, напримерс большими массивами).

Другие советы

В общем, гибкий, быстрый и питонический способ обработки неизвестных типов - это просто выполнить над ними некоторую операцию и перехватить исключение для недопустимых типов.

try:
    a = 5+'5'
except TypeError:
    print "Oops"

Мне кажется, что такой подход проще, чем специальное выделение какой-либо функции для определения абсолютной достоверности типа.

Кроме того, numpy имеет numpy.isreal и другие подобные функции (numpy.is На вкладке + должен быть их список).

У всех них есть свои забавные кейсы, но один из них может оказаться полезным.

Ваш is_numeric является нечетко определенным.Смотрите мои комментарии к вашему вопросу.

Другими числовыми типами могут быть: long, complex, fractions.Fraction, numpy.bool_, numpy.ubyte, ...

operator.isNumberType() ВОЗВРАТ True для чисел Python и numpy.array.

Начиная с Python 2.6, вы можете использовать isinstance(d, numbers.Number) вместо устаревшего operator.isNumberType().

Как правило, лучше проверять возможности объекта (например, можете ли вы добавить к нему целое число), а не его тип.

isinstance(numpy.int32(4), numbers.Number) ВОЗВРАТ False, так что это не совсем работает. operator.isNumberType() однако работает со всеми вариантами numpy numbers, включая numpy.array([1]).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top