La identificación numérica y tipos de matriz en numpy
Pregunta
Hay una función existente en numpy que me va a decir si un valor es de tipo numérico o una colección de matriz?Estoy escribiendo algunos de procesamiento de datos de código que necesita para manejar los números en diferentes representaciones (por "número de" me refiero a cualquier representación de un numérico de la cantidad que se puede manipular con el estándar de los operadores aritméticos, +, -, *, /, **).
Algunos ejemplos de comportamiento que estoy buscando
>>> 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
Si no hay tal función existe, sé que no debería ser difícil para escribir uno, algo así como
isinstance(n, (int, float, decimal.Decimal, numpy.number, numpy.ndarray))
pero hay otros tipos numéricos que debo incluir en la lista?
Solución
Como han respondido otros, podría haber otros tipos numéricos además de los que mencionas. Un enfoque sería verificar explícitamente las capacidades que desea, con algo como
# 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)
Esto funciona para todos sus ejemplos, excepto el último, numpy.array(['1'])
. Esto se debe a que numpy.ndarray
tiene los métodos especiales para las operaciones numéricas, pero genera TypeError si intenta usarlos de manera inapropiada con cadenas o matrices de objetos. Puede agregar una verificación explícita para esto como
... and not (isinstance(obj, ndarray) and obj.dtype.kind in 'OSU')
Esto puede ser lo suficientemente bueno.
Pero ... nunca se puede estar 100% seguro de que alguien no definirá otro tipo con el mismo comportamiento, por lo que una forma más infalible es tratar de hacer un cálculo y capturar el excepción, algo así como
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
pero dependiendo de la frecuencia con la que pienses usarlo y con qué argumentos, esto puede no ser práctico (puede ser potencialmente lento, por ejemplo, con matrices grandes).
Otros consejos
En general, la forma flexible, rápida y pitónica de manejar tipos desconocidos es simplemente realizar alguna operación en ellos y detectar una excepción en los tipos no válidos.
try:
a = 5+'5'
except TypeError:
print "Oops"
Me parece que este enfoque es más fácil que el uso especial de algunas funciones para determinar la certeza absoluta de tipo.
También, numpy ha numpy.isreal
y otras funciones similares (numpy.is
+ Ficha debe tener una lista de ellos).
Todos ellos tienen su diversión casos de esquina pero uno de los que podría ser útil.
Su is_numeric
está mal definido. Vea mis comentarios a su pregunta.
Otros tipos numéricos pueden ser: long
, complex
, fractions.Fraction
, numpy.bool_
, numpy.ubyte
, ...
operator.isNumberType()
devuelve True
para números de Python y numpy.array
.
Desde Python 2.6 puede usar isinstance(d, numbers.Number)
en lugar de obsoleto <=>.
Generalmente es mejor verificar las capacidades del objeto (por ejemplo, si puede agregarle un número entero) y no su tipo.
isinstance(numpy.int32(4), numbers.Number)
devuelve False
, por lo que eso no funciona del todo. operator.isNumberType()
funciona en todas las variantes de números numpy, sin embargo, incluyendo numpy.array([1])
.