Domanda

Esiste una funzione esistente in numpy che mi dirà se un valore è un tipo numerico o un array numpy? Sto scrivendo un codice di elaborazione dati che deve gestire i numeri in diverse rappresentazioni (per & Quot; numero & Quot; intendo qualsiasi rappresentazione di una quantità numerica che può essere manipolata usando gli operatori aritmetici standard, + , -, *, /, **).

Alcuni esempi del comportamento che sto cercando

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

Se non esiste tale funzione, so che non dovrebbe essere difficile scriverne una, qualcosa del genere

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

ma ci sono altri tipi numerici che dovrei includere nell'elenco?

È stato utile?

Soluzione

Come altri hanno risposto, potrebbero esserci altri tipi numerici oltre a quelli che hai citato. Un approccio sarebbe quello di verificare esplicitamente le funzionalità desiderate, con qualcosa come

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

Funziona con tutti i tuoi esempi tranne l'ultimo, numpy.array(['1']). Questo perché numpy.ndarray ha i metodi speciali per le operazioni numeriche ma genera TypeError se si tenta di usarli in modo inappropriato con array di stringhe o oggetti. Puoi aggiungere un controllo esplicito per questo come

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

Questo potrebbe essere abbastanza buono.

Ma ... non puoi mai essere 100% sicuro che qualcuno non definirà un altro tipo con lo stesso comportamento, quindi un modo più infallibile è effettivamente provare a fare un calcolo e catturare il eccezione, qualcosa come

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

ma a seconda della frequenza con cui prevedi di usarlo e con quali argomenti, questo potrebbe non essere pratico (può essere potenzialmente lento, ad esempio con array di grandi dimensioni).

Altri suggerimenti

In generale, il modo flessibile, veloce e pitonico per gestire i tipi sconosciuti è semplicemente eseguire alcune operazioni su di essi e catturare un'eccezione sui tipi non validi.

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

Mi sembra che questo approccio sia più facile che definire alcune funzioni per determinare la certezza assoluta del tipo.

Inoltre, numpy ha numpy.isreal e altre funzioni simili (numpy.is + Tab dovrebbe elencarle).

Hanno tutti i loro divertenti astucci d'angolo, ma uno di questi potrebbe essere utile.

Il tuo is_numeric è mal definito. Vedi i miei commenti alla tua domanda.

Altri tipi numerici potrebbero essere: long, complex, fractions.Fraction, numpy.bool_, numpy.ubyte, ...

operator.isNumberType() restituisce True per i numeri Python e numpy.array.

Da Python 2.6 puoi usare isinstance(d, numbers.Number) invece di deprecato <=>.

Generalmente è meglio verificare le capacità dell'oggetto (ad es. se è possibile aggiungere un numero intero ad esso) e non il suo tipo.

isinstance(numpy.int32(4), numbers.Number) restituisce False, quindi non funziona del tutto. operator.isNumberType() funziona su tutte le varianti di numeri intorpiditi, tuttavia, compreso numpy.array([1]).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top