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


103

입력에 숫자가 아닌 값이 하나 이상 포함되어 있는지 감지하는 함수를 작성해야합니다. 숫자가 아닌 값이 발견되면 오류가 발생합니다 (계산은 숫자 값만 반환해야하기 때문). 입력 배열의 차원 수는 미리 알 수 없습니다. 함수는 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

3
에 대한 설명 contains_nan이 의심스러워 보입니다. "숫자가 아닌 값이 하나 이상있는 경우 false를 반환합니다." 배열에 NaN이 포함되어 있으면 contains_nan반환 True할 것으로 예상했을 것 입니다.
Samuel Tardieu

다음과 같은 입력은 array(['None', 'None'], dtype=object)어떻습니까? 이러한 입력이 예외를 발생시켜야합니까?
Finn Årup Nielsen 2015-06-08

사용하지 마십시오 float('nan') in x. 작동하지 않습니다.
Charlie Parker

답변:


183

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

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 패턴 화 된 ()와 버전은 첫 번째로 빠른 속도로 두 번 밖에입니다
기독교 가이어

float('nan') in x작동 하지 않는 이유는 무엇 입니까? 나는 그것을 시도했고 파이썬은 False어디에 x = [1,2,3,float('nan')].
Charlie Parker

1
@CharlieParker는 float ( 'nan') == float ( 'nan')이 False를 반환하는 것과 같은 이유입니다. NaN은 NaN과 같지 않습니다. 여기 더 많은 정보 : stackoverflow.com/questions/10034149/…
Muppet

1
@mab : 그 이유 numpy.any는 genexp를 호출 하면 genexp 만 반환 되기 때문입니다 . 당신은 실제로 당신이 생각하는 계산을하는 것이 아닙니다. numpy.anygenexp를 호출하지 마십시오 .
user2357112 모니카 지원

실제 디버깅 시나리오에서는 숫자 오버플로, 불안정성 등을 탐지하는 np.isfinite대신 살펴 보는 것이 좋습니다 np.isnan.
Ben Usman

18

무한대가 가능한 값이면 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)

float('nan') in x작동 하지 않는 이유는 무엇 입니까? 나는 그것을 시도했고 파이썬은 False어디에 x = [1,2,3,float('nan')].
Charlie Parker

1
@CharlieParker nan는 두 s가 서로 같지 않은 것으로 간주 되기 때문 입니다. 시도해보십시오 float('nan') == float('nan').
Akavall 2016 년

흥미 롭군요. 왜 동등하지 않은 것으로 간주됩니까?
Charlie Parker

1
@CharlieParker, 여기에 아주 좋은 대답을 줄 수 없다고 생각합니다. 어쩌면 이것은 당신이 찾고있는 무엇 : stackoverflow.com/questions/1565164/...
Akavall

4

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


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


float('nan') in x작동 하지 않는 이유는 무엇 입니까? 나는 그것을 시도했고 파이썬은 False어디에 x = [1,2,3,float('nan')].
Charlie Parker

@CharlieParker ... NAN과의 비교가 예상 한대로 작동하지 않기 때문입니다. NAN은 논리적 NULL (= 모름)처럼 취급됩니다. float("nan")==float("nan")False(하지만 실행 가능하게 아마 NAN 또는 없음을 반환해야합니다). 마찬가지로 NAN 및 boolen NULL의 이상성은 SQL을 포함한 많은 언어에서 참입니다 (NULL = NULL은 참이 아님).
user48956

2

(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"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.