2009-05-26 16 views
48

Ho bisogno di scrivere una funzione che rilevi se l'input contiene almeno un valore che non è numerico. Se viene rilevato un valore non numerico, verrà generato un errore (poiché il calcolo deve restituire solo un valore numerico). Il numero di dimensioni della matrice di input non è noto in anticipo - la funzione dovrebbe fornire il valore corretto indipendentemente da ndim. Come ulteriore complicazione, l'input potrebbe essere un singolo float o numpy.float64 o anche qualcosa di strano come un array a dimensione zero.Rileva se una matrice NumPy contiene almeno un valore non numerico?

Il modo ovvio per risolvere questo è scrivere una funzione ricorsiva che itera su ogni oggetto iterabile dell'array fino a quando non trova una non-iterabe. Applicherà la funzione numpy.isnan() su ogni oggetto non iterable. Se viene trovato almeno un valore non numerico, la funzione restituirà False immediatamente. Altrimenti se tutti i valori nel iterabile sono numerici, alla fine restituirà True.

Che funziona bene, ma è piuttosto lento e mi aspetto che NumPy abbia un modo molto migliore per farlo. Qual è un'alternativa più veloce e più numpy?

Ecco la mia mockup:

def contains_nan(myarray): 
    """ 
    @param myarray : An n-dimensional array or a single float 
    @type myarray : numpy.ndarray, numpy.array, float 
    @returns: bool 
    Returns true if myarray is numeric or only contains numeric values. 
    Returns false if at least one non-numeric value exists 
    Not-A-Number is given by the numpy.isnan() function. 
    """ 
    return True 
+3

tua descrizione per 'contains_nan' sembra sospetto: "Restituisce false se esiste almeno un valore non numerico". Mi sarei aspettato che 'contains_nan' restituisse' True' se la matrice contiene NaN. –

+0

Che dire di input come 'array (['None', 'None'], dtype = object)'? Questo input dovrebbe sollevare un'eccezione? –

+0

NON usare 'float ('nan') in x'. Non funziona. –

risposta

78

questo dovrebbe essere più veloce di iterazione e funziona indipendentemente dalla forma.

numpy.isnan(myarray).any() 

Edit: 30x più veloce:

import timeit 
s = 'import numpy;a = numpy.arange(10000.).reshape((100,100));a[10,10]=numpy.nan' 
ms = [ 
    'numpy.isnan(a).any()', 
    'any(numpy.isnan(x) for x in a.flatten())'] 
for m in ms: 
    print " %.2f s" % timeit.Timer(m, s).timeit(1000), m 

Risultati:

0.11 s numpy.isnan(a).any() 
    3.75 s any(numpy.isnan(x) for x in a.flatten()) 

Bonus: tutto funziona bene per non-matrice tipi NumPy:

>>> a = numpy.float64(42.) 
>>> numpy.isnan(a).any() 
False 
>>> a = numpy.float64(numpy.nan) 
>>> numpy.isnan(a).any() 
True 
+0

con numpy 1.7 la versione flatten() è solo due volte più veloce della prima –

+0

Perché qualcosa come "float ('nan') in x' non funziona? L'ho provato e python restituisce 'False' dove' x = [1,2,3, float ('nan')] '. –

+1

@CharlieParker lo stesso motivo per cui float ('nan') == float ('nan') restituirà False. NaN non è uguale a NaN. Qui maggiori informazioni: http://stackoverflow.com/questions/10034149/why-is-nan-not-equal-to-nan – Muppet

3

Con numpy 1.3 oppure svn puoi farlo

In [1]: a = arange(10000.).reshape(100,100) 

In [3]: isnan(a.max()) 
Out[3]: False 

In [4]: a[50,50] = nan 

In [5]: isnan(a.max()) 
Out[5]: True 

In [6]: timeit isnan(a.max()) 
10000 loops, best of 3: 66.3 µs per loop 

Il trattamento di nans nei confronti non era coerente nelle versioni precedenti.

+0

Perché qualcosa come "float ('nan') in x' non funziona? L'ho provato e python restituisce 'False' dove' x = [1,2,3, float ('nan')] '. –

+0

@CharlieParker ... perché il confronto con NAN non fa quello che ti aspetti. NAN è trattato come un NULL logico (= non so). 'float (" nan ") == float (" nan ")' dà 'False' (anche se probabilmente dovrebbe restituire NAN o None). Analogamente la stranezza con NAN e il valore NULL boolen è vero in molte lingue, incluso SQL (dove NULL = NULL non è mai vero). – user48956

9

Se infinito è un possibile valore, userei numpy.isfinite

numpy.isfinite(myarray).all() 

Se le Esamina sopra a True, quindi myarray non contiene, numpy.nan, numpy.inf o -numpy.inf valori.

numpy.nan sarà OK con numpy.inf valori, ad esempio:

In [11]: import numpy as np 

In [12]: b = np.array([[4, np.inf],[np.nan, -np.inf]]) 

In [13]: np.isnan(b) 
Out[13]: 
array([[False, False], 
     [ True, False]], dtype=bool) 

In [14]: np.isfinite(b) 
Out[14]: 
array([[ True, False], 
     [False, False]], dtype=bool) 
+0

Perché non qualcosa come 'float ('nan') in x' non funziona? L'ho provato e python restituisce 'False' dove' x = [1,2,3, float ('nan')] '. –

+1

@CharlieParker perché due 'nan's non sono considerati uguali tra loro. Prova 'float ('nan') == float ('nan')'. – Akavall

+0

interessante. Perché non sono considerati uguali? –

2

(np.where(np.isnan(A)))[0].shape[0] sarà maggiore di 0 se A contiene almeno un elemento di nan, A potrebbe essere una matrice n x m.

Esempio:

import numpy as np 

A = np.array([1,2,4,np.nan]) 

if (np.where(np.isnan(A)))[0].shape[0]: 
    print "A contains nan" 
else: 
    print "A does not contain nan" 
Problemi correlati