Phát hiện xem một mảng NumPy có chứa ít nhất một giá trị không phải là số không?


103

Tôi cần viết một hàm sẽ phát hiện xem đầu vào có chứa ít nhất một giá trị không phải là số hay không. Nếu một giá trị không phải số được tìm thấy, tôi sẽ báo lỗi (vì phép tính chỉ trả về giá trị số). Số lượng kích thước của mảng đầu vào không được biết trước - hàm phải cung cấp giá trị chính xác bất kể ndim. Như một sự phức tạp bổ sung, đầu vào có thể là một float đơn lẻ numpy.float64hoặc thậm chí là một thứ gì đó kỳ quặc như mảng không chiều.

Cách rõ ràng để giải quyết vấn đề này là viết một hàm đệ quy lặp lại trên mọi đối tượng có thể lặp lại trong mảng cho đến khi nó tìm thấy một không lặp. Nó sẽ áp dụng numpy.isnan()chức năng trên mọi đối tượng không thể lặp lại. Nếu ít nhất một giá trị không phải là số được tìm thấy thì hàm sẽ trả về False ngay lập tức. Ngược lại, nếu tất cả các giá trị trong biến có thể lặp lại là số thì cuối cùng nó sẽ trả về True.

Điều đó hoạt động tốt, nhưng nó khá chậm và tôi hy vọng rằng NumPy có cách tốt hơn nhiều để làm điều đó. Đâu là giải pháp thay thế nhanh hơn và nhiều hơn?

Đây là mô hình của tôi:

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
Mô tả của bạn cho có contains_nanvẻ đáng ngờ: "Trả về false nếu tồn tại ít nhất một giá trị không phải số". Tôi đã mong đợi sẽ contains_nantrả về Truenếu mảng chứa NaN.
Samuel Tardieu

Điều gì về đầu vào chẳng hạn như array(['None', 'None'], dtype=object)? Một đầu vào như vậy có nên chỉ nêu ra một ngoại lệ không?
Finn Årup Nielsen

KHÔNG sử dụng float('nan') in x. Nó không hoạt động.
Charlie Parker

Câu trả lời:


182

Điều này sẽ nhanh hơn việc lặp lại và sẽ hoạt động bất kể hình dạng.

numpy.isnan(myarray).any()

Chỉnh sửa: nhanh hơn 30 lần:

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

Các kết quả:

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

Phần thưởng: nó hoạt động tốt cho các loại NumPy không phải mảng:

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

1
với NumPy 1,7 các flatten () phiên bản là chỉ hai lần nhanh như người đầu tiên
Christian Geier

Tại sao một cái gì đó float('nan') in xkhông giống như không hoạt động? Tôi đã thử nó và python trở lại Falseở đâu x = [1,2,3,float('nan')].
Charlie Parker

1
@CharlieParker cùng một lý do tại sao float ('nan') == float ('nan') sẽ trả về False. NaN không bằng NaN. Tại đây thêm thông tin: stackoverflow.com/questions/10034149/…
Muppet

1
@mab: Đó là bởi vì việc gọi numpy.anygenexp chỉ trả về genexp; bạn không thực sự thực hiện tính toán mà bạn nghĩ. Không bao giờ gọi numpy.anymột genxp.
user2357112 hỗ trợ Monica

Trong kịch bản gỡ lỗi thực, tôi cũng sẽ khuyên bạn nên nhìn vào np.isfinitethay vì np.isnanđể phát hiện tràn số, không ổn định, vv
Bến Usman

18

Nếu vô cực là một giá trị có thể, tôi sẽ sử dụng numpy.isfinite

numpy.isfinite(myarray).all()

Nếu đánh giá lại ở trên để True, sau đó myarraykhông chứa, numpy.nan, numpy.infhoặc -numpy.infgiá trị.

numpy.nansẽ OK với numpy.infcác giá trị, ví dụ:

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)

Tại sao một cái gì đó float('nan') in xkhông giống như không hoạt động? Tôi đã thử nó và python trở lại Falseở đâu x = [1,2,3,float('nan')].
Charlie Parker

1
@CharlieParker vì hai nans không được coi là bằng nhau. Cố gắng float('nan') == float('nan').
Akavall

hấp dẫn. Tại sao họ không được coi là bình đẳng?
Charlie Parker

1
@CharlieParker, tôi không nghĩ mình có thể đưa ra câu trả lời hay ở đây. Có lẽ đây là những gì bạn đang tìm kiếm: stackoverflow.com/questions/1565164/...
Akavall

4

Pfft! Micro giây! Không bao giờ giải quyết một vấn đề trong micro giây mà có thể được giải quyết trong nano giây.

Lưu ý rằng câu trả lời được chấp nhận:

  • lặp lại trên toàn bộ dữ liệu, bất kể có tìm thấy nan hay không
  • tạo một mảng tạm thời có kích thước N, mảng này là dư thừa.

Một giải pháp tốt hơn là trả về True ngay lập tức khi tìm thấy NAN:

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)

và hoạt động cho n-thứ nguyên:

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

So sánh điều này với giải pháp gốc 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

Phương pháp thoát lệnh sớm là 3 lệnh hoặc tăng tốc độ (trong một số trường hợp). Không quá tồi cho một chú thích đơn giản.


3

Với numpy 1.3 hoặc svn, bạn có thể làm điều này

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

Việc xử lý các nans trong các so sánh không nhất quán trong các phiên bản trước đó.


Tại sao một cái gì đó float('nan') in xkhông giống như không hoạt động? Tôi đã thử nó và python trở lại Falseở đâu x = [1,2,3,float('nan')].
Charlie Parker

@CharlieParker ... vì so sánh với NAN không làm được những gì bạn mong đợi. NAN được coi như một NULL logic (= không biết). float("nan")==float("nan")đưa ra False(mặc dù khả thi nó có thể trả về NAN hoặc Không có). Tương tự, sự kỳ lạ với NAN và boolen NULL là đúng trong nhiều ngôn ngữ, kể cả SQL (trong đó NULL = NULL không bao giờ đúng).
user48956

2

(np.where(np.isnan(A)))[0].shape[0]sẽ lớn hơn 0nếu Achứa ít nhất một phần tử của nan, Acó thể là một n x mma trận.

Thí dụ:

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"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.