wake-up-neo.com

Ermitteln, ob ein NumPy-Array mindestens einen nicht numerischen Wert enthält?

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
82
Salim Fadhley

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

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)
13
Akavall

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.

3
chuck

(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"
2
Ting On Chan

Pfft! Mikrosekunden! Lösen Sie niemals ein Problem in Mikrosekunden, das in Nanosekunden gelöst werden kann.

Beachten Sie, dass die akzeptierte Antwort:

  • iteriert über die gesamten Daten, unabhängig davon, ob eine Nan gefunden wird
  • erstellt ein temporäres Array der Größe N, das redundant ist.

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.

1
user48956