[python] NumPy 배열에 숫자가 아닌 값이 하나 이상 포함되어 있는지 감지 하시겠습니까?

입력에 숫자가 아닌 값이 하나 이상 포함되어 있는지 감지하는 함수를 작성해야합니다. 숫자가 아닌 값이 발견되면 오류가 발생합니다 (계산은 숫자 값만 반환해야하기 때문). 입력 배열의 차원 수는 미리 알 수 없습니다. 함수는 ndim에 관계없이 올바른 값을 제공해야합니다. 추가 복잡함으로 입력은 단일 플로트 또는 numpy.float640 차원 배열과 같은 이상한 무언가 일 수 있습니다 .

이 문제를 해결하는 확실한 방법은 비 iterabe를 찾을 때까지 배열의 모든 반복 가능한 객체를 반복하는 재귀 함수를 작성하는 것입니다. numpy.isnan()반복 불가능한 모든 객체에 함수를 적용 합니다. 숫자가 아닌 값이 하나 이상 발견되면 함수는 즉시 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



답변

이것은 반복하는 것보다 빠르며 모양에 관계없이 작동합니다.

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


답변

무한대가 가능한 값이면 numpy.isfinite를 사용 합니다.

numpy.isfinite(myarray).all()

위의 평가가 True이면 myarrayno numpy.nan, numpy.inf또는 -numpy.inf값이 포함 됩니다.

numpy.nan함께 OK 것 numpy.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)


답변

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 차 또는 규모 속도 향상입니다 (경우에 따라). 단순한 주석에 너무 초라하지 않습니다.


답변

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의 처리는 이전 버전에서 일관되지 않았습니다.


답변

(np.where(np.isnan(A)))[0].shape[0]보다 커야 할 0경우 A중 적어도 하나 개의 원소를 포함 nan, A될 수 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"


답변