vote up 2 vote down
star

Is there an existing function in numpy that will tell me if a value is either a numeric type or a numpy array? I'm writing some data-processing code which needs to handle numbers in several different representations (by "number" I mean any representation of a numeric quantity which can be manipulated using the standard arithmetic operators, +, -, *, /, **).

Some examples of the behavior I'm looking for

>>> 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

If no such function exists, I know it shouldn't be hard to write one, something like

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

but are there other numeric types I should include in the list?

flag
comments (4)

4 Answers:

vote up 2 vote down
check

As others have answered, there could be other numeric types besides the ones you mention. One approach would be to check explicitly for the capabilities you want, with something like

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

This works for all your examples except the last one, numpy.array(['1']). That's because numpy.ndarray has the special methods for numeric operations but raises TypeError if you try to use them inappropriately with string or object arrays. You could add an explicit check for this like

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

This may be good enough.

But... you can never be 100% sure that somebody won't define another type with the same behavior, so a more foolproof way is to actually try to do a calculation and catch the exception, something like

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

but depending on how often you plan to call use it and with what arguments, this may not be practical (it can be potentially slow, e.g. with large arrays).

link|flag
add comment
vote up 3 vote down

In general, the flexible, fast, and pythonic way to handle unknown types is to just perform some operation on them and catch an exception on invalid types.

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

Seems to me that this approach is easier than special-casing out some function to determine absolute type certainty.

link|flag
comments (4)
vote up 0 vote down

You can use type():

>>> a=scipy.array([1,2,3,4])
>>> b=array.array('L')
>>> type(a)
<type 'numpy.ndarray'>
>>> type(b)
<type 'array.array'>
>>> c=10.5
>>> type(c) in scipy.ScalarType
True
>>>
link|flag
add comment
vote up 0 vote down

Your is_numeric is ill-defined. See my comments to your question.

Other numerical types could be: long, complex, fractions.Fraction, numpy.bool_, numpy.ubyte, ...

operator.isNumberType() returns True for Python numbers and numpy.array.

Since Python 2.6 you can use isinstance(d, numbers.Number) instead of deprecated operator.isNumberType().

Generally it is better to check the capabilities of the object (e.g., whether you can add an integer to it) and not its type.

link|flag
comments (1)

Your Answer:

Get an OpenID
or

Not the answer you're looking for? Browse other questions tagged or ask your own question.