web-dev-qa-db-ja.com

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

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

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

それはうまく動作しますが、それはかなり遅いですし、 NumPy がそれを行うためのはるかに良い方法を持っていると期待しています。より速く、よりnumpyishである代替手段は何ですか?

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

_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

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

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

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

numpy.isfinite(myarray).all()

上記の評価がTrueの場合、myarrayにはno、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)
13
Akavall

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

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

3
chuck

Ananの要素が少なくとも1つ含まれる場合、(np.where(np.isnan(A)))[0].shape[0]0より大きくなります。An 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"
2
Ting On Chan

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

受け入れられた答えに注意してください:

  • 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

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

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桁または大幅に高速化されます(場合によって)。単純な注釈としてはあまりに粗末ではありません。

1
user48956