Ich muss eine Funktion schreiben, die erkennt, ob die Eingabe mindestens einen nicht numerischen Wert enthält. Wenn ein nicht numerischer Wert gefunden wird, werde ich einen Fehler auslösen (da die Berechnung nur einen numerischen Wert zurückgeben sollte). Die Anzahl der Dimensionen des Eingabearrays ist nicht im Voraus bekannt - die Funktion sollte unabhängig von ndim den richtigen Wert angeben. Als zusätzliche Komplikation kann die Eingabe ein einzelnes Float oder numpy.float64
Oder sogar ein seltsames Element wie ein nulldimensionales Array sein.
Der naheliegende Weg, dies zu lösen, besteht darin, eine rekursive Funktion zu schreiben, die jedes iterierbare Objekt im Array durchläuft, bis es eine Nicht-Iteration findet. Die Funktion numpy.isnan()
wird auf jedes nicht iterierbare Objekt angewendet. Wenn mindestens ein nicht numerischer Wert gefunden wird, gibt die Funktion sofort False zurück. Andernfalls wird True zurückgegeben, wenn alle Werte in der Iterationsdatei numerisch sind.
Das funktioniert gut, aber es ist ziemlich langsam und ich gehe davon aus, dass NumPy einen viel besseren Weg hat, es zu tun. Was ist eine Alternative, die schneller und benommener ist?
Hier ist mein Modell:
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
Dies sollte schneller als die Iteration sein und funktioniert unabhängig von der Form.
numpy.isnan(myarray).any()
Bearbeiten: 30x schneller:
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
Ergebnisse:
0.11 s numpy.isnan(a).any()
3.75 s any(numpy.isnan(x) for x in a.flatten())
Bonus: Es funktioniert gut für Nicht-Array-NumPy-Typen:
>>> a = numpy.float64(42.)
>>> numpy.isnan(a).any()
False
>>> a = numpy.float64(numpy.nan)
>>> numpy.isnan(a).any()
True
Wenn Unendlich ein möglicher Wert ist, würde ich numpy.isfinite verwenden
numpy.isfinite(myarray).all()
Wenn das obige Ergebnis zu True
ausgewertet wird, enthält myarray
keine, numpy.nan
-, numpy.inf
- oder -numpy.inf
- Werte.
numpy.nan
Ist in Ordnung mit numpy.inf
Werten, zum Beispiel:
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)
Mit NumPy 1.3 oder SVN können Sie dies tun
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
Die Behandlung von Nans in Vergleichen war in früheren Versionen nicht konsistent.
(np.where(np.isnan(A)))[0].shape[0]
Ist größer als 0
, Wenn A
mindestens ein Element von nan
enthält, A
könnte ein n x m
Matrix.
Beispiel:
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"
Pfft! Mikrosekunden! Lösen Sie niemals ein Problem in Mikrosekunden, das in Nanosekunden gelöst werden kann.
Beachten Sie, dass die akzeptierte Antwort:
Eine bessere Lösung ist die sofortige Rückgabe von True, wenn NAN gefunden wird:
import numba
import numpy as np
NAN = float("nan")
@numba.njit(nogil=True)
def _any_nans(a):
for x in a:
if np.isnan(x): return True
return False
@numba.jit
def any_nans(a):
if not a.dtype.kind=='f': return False
return _any_nans(a.flat)
array1M = np.random.Rand(1000000)
assert any_nans(array1M)==False
%timeit any_nans(array1M) # 573us
array1M[0] = NAN
assert any_nans(array1M)==True
%timeit any_nans(array1M) # 774ns (!nanoseconds)
und funktioniert für n-Dimensionen:
array1M_nd = array1M.reshape((len(array1M)/2, 2))
assert any_nans(array1M_nd)==True
%timeit any_nans(array1M_nd) # 774ns
Vergleichen Sie dies mit der nativen numpy-Lösung:
def any_nans(a):
if not a.dtype.kind=='f': return False
return np.isnan(a).any()
array1M = np.random.Rand(1000000)
assert any_nans(array1M)==False
%timeit any_nans(array1M) # 456us
array1M[0] = NAN
assert any_nans(array1M)==True
%timeit any_nans(array1M) # 470us
%timeit np.isnan(array1M).any() # 532us
Die Early-Exit-Methode ist eine Beschleunigung um 3 Ordnungen oder eine Größenordnung (in einigen Fällen). Nicht zu schäbig für eine einfache Anmerkung.