NumPy配列に少なくとも1つの非数値が含まれているかどうかを検出しますか?


103

入力に数値以外の値が少なくとも1つ含まれているかどうかを検出する関数を作成する必要があります。数値以外の値が見つかった場合は、エラーが発生します(計算では数値のみが返されるため)。入力配列の次元数は事前にわかっていません-関数はndimに関係なく正しい値を与える必要があります。追加の複雑さとして、入力は単一の浮動小数点数、numpy.float64またはゼロ次元配列のような奇妙なボールでさえあります。

これを解決する明白な方法は、非反復が見つかるまで配列内のすべての反復可能なオブジェクトを反復する再帰関数を記述することです。これは、numpy.isnan()すべての反復不可能なオブジェクトに関数を適用します。少なくとも1つの非数値が見つかった場合、関数はすぐにFalseを返します。それ以外の場合、イテラブルのすべての値が数値の場合、最終的にTrueを返します。

これは問題なく動作しますが、非常に遅く、NumPyを使用する方がはるかに優れた方法であると思います。より速く、より派手な代替手段は何ですか?

これが私のモックアップです:

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
の説明contains_nanは不審に見えます:「少なくとも1つの非数値が存在する場合はfalseを返します」。配列にNaNが含まれている場合は、contains_nan返されるはずTrueです。
Samuel Tardieu、

などの入力はどうarray(['None', 'None'], dtype=object)ですか?そのような入力は単に例外を発生させるべきですか?
FinnÅrupNielsen 2015

使用しないでください float('nan') in x。それは動作しません。
チャーリーパーカー

回答:


182

これは反復よりも高速で、形状に関係なく機能します。

numpy.isnan(myarray).any()

編集:30倍高速:

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

結果:

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

おまけ:配列以外のNumPy型では問題なく機能します。

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

1
numpy 1.7では、flatten()バージョンは最初のバージョンの2倍の速度しかありません
Christian Geier

なぜ動作しないようなのfloat('nan') in xですか?私はそれを試しました、そして、PythonはFalseどこに戻りますx = [1,2,3,float('nan')]
チャーリーパーカー

1
@CharlieParkerは、float( 'nan')== float( 'nan')がFalseを返すのと同じ理由です。NaNはNaNと等しくありません。詳細:stackoverflow.com/questions/10034149/...
マペット

1
@mab:これnumpy.anyは、genexpを呼び出すとgenexpが返されるためです。自分が思っているような計算を実際に行っているわけではありません。numpy.anygenexpを呼び出さないでください。
user2357112は2017

実際のデバッグのシナリオでは、私も見て推薦するnp.isfinite代わりにnp.isnanなど、数値オーバーフロー、不安定性を検出するために
ベン・ウスマン

18

無限大が可能な値である場合、私はnumpy.isfiniteを使用します

numpy.isfinite(myarray).all()

上記評価さにした場合True、その後myarray、何も含まれていないnumpy.nannumpy.infまたは-numpy.inf値。

numpy.nannumpy.inf値で問題ありません。次に例を示します。

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)

なぜ動作しないようなのfloat('nan') in xですか?私はそれを試しました、そして、PythonはFalseどこに戻りますx = [1,2,3,float('nan')]
チャーリーパーカー

1
@CharlieParkerは、2つnanのが互いに等しいとは見なされないためです。お試しくださいfloat('nan') == float('nan')
Akavall 2016年

面白い。なぜ彼らは等しいと見なされないのですか?
チャーリーパーカー

1
@CharlieParker、私はここで非常に良い答えを出すことができるとは思いません。多分これはあなたが探しているものです。stackoverflow.com/questions/1565164/...
Akavall

4

うん!マイクロ秒!ナノ秒単位で解決できるマイクロ秒単位の問題は決して解決しないでください。

受け入れられた答えは:

  • nanが見つかったかどうかに関係なく、データ全体を反復します
  • 冗長なサイズNの一時配列を作成します。

より良い解決策は、NANが見つかったときにすぐにTrueを返すことです。

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)

n次元で機能します。

array1M_nd = array1M.reshape((len(array1M)/2, 2))
assert any_nans(array1M_nd)==True
%timeit any_nans(array1M_nd)  # 774ns

これを派手なネイティブソリューションと比較してください。

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

早期終了方法は、3桁以上の高速化です(場合によっては)。単純なアノテーションとしては、それほど粗末ではありません。


3

numpy 1.3またはsvnでこれを行うことができます

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

比較におけるナンの扱いは、以前のバージョンでは一貫していませんでした。


なぜ動作しないようなのfloat('nan') in xですか?私はそれを試しました、そして、PythonはFalseどこに戻りますx = [1,2,3,float('nan')]
チャーリーパーカー

@CharlieParker ... NANとの比較では期待どおりの結果が得られないため。NANは論理NULL(=わからない)のように扱われます。 float("nan")==float("nan")与えますFalse(可能であれば、おそらくNANまたはNoneを返すはずです)。同様に、NANとブールNULLの奇妙さは、SQLを含む多くの言語で真です(NULL = NULLは決して真ではありません)。
user48956 2017年

2

(np.where(np.isnan(A)))[0].shape[0]大きくなる0場合Aの少なくとも1種の元素を含有するnanAとすることができるn x mマトリックス。

例:

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"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.