2009-05-26 28 views
48

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ố không. Nếu tìm thấy một giá trị không phải là số, tôi sẽ đưa ra một lỗi (vì phép tính chỉ trả về một giá trị số). Số thứ nguyên của mảng đầu vào không được biết trước - hàm sẽ cung cấp giá trị chính xác bất kể ndim là gì. Như một biến chứng thêm, đầu vào có thể là một phao đơn hoặc numpy.float64 hoặc thậm chí một cái gì đó kỳ quặc như một mảng không theo chiều.Phát hiện nếu một mảng NumPy có chứa ít nhất một giá trị không phải là số không?

Cách rõ ràng để giải quyết điều 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 không lặp lại. Nó sẽ áp dụng hàm numpy.isnan() trên mọi đối tượng không thể lặp lại. Nếu tìm thấy ít nhất một giá trị không phải là số thì hàm sẽ trả về False ngay lập tức. Nếu không, nếu tất cả các giá trị trong iterable là số thì cuối cùng nó sẽ trả về True.

Điều đó chỉ 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 để thực hiện điều đó. Một giải pháp thay thế nhanh hơn và gọn gàng hơn là gì?

Dưới đây là mockup 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 'contains_nan' có vẻ khả nghi: "Trả về false nếu ít nhất một giá trị không phải số tồn tại". Tôi đã có thể mong đợi 'contains_nan' để trả về' True' nếu mảng chứa NaN. –

+0

Điều gì về các đầu vào như 'mảng (['Không', 'Không'], dtype = object)'? Nên một đầu vào như vậy chỉ cần tăng một ngoại lệ? –

+0

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

Trả lời

78

này cần được nhanh hơn so với đi làm lại và sẽ làm việc bất kể hình dạng.

numpy.isnan(myarray).any() 

Edit: 30x nhanh hơ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 

Kết quả:

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

Bonus: nó hoạt động tốt cho phi mảng NumPy loại:

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

với numpy 1.7 phiên bản flatten() chỉ nhanh gấp hai lần cái đầu tiên –

+0

Tại sao không giống như 'float ('nan') trong x' không hoạt động? Tôi đã thử nó và python trả về 'False' trong đó' x = [1,2,3, float ('nan')] '. –

+1

@CharlieParker cùng một lý do tại sao phao ('nan') == phao ('nan') sẽ trả về Sai. NaN không bằng NaN. Ở đây có thêm thông tin: http://stackoverflow.com/questions/10034149/why-is-nan-not-equal-to-nan – Muppet

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 so sánh không nhất quán trong các phiên bản trước đó.

+0

Tại sao không có cái gì đó như 'phao ('nan') trong x' không hoạt động? Tôi đã thử nó và python trả về 'False' trong đó' x = [1,2,3, float ('nan')] '. –

+0

@CharlieParker ... vì so sánh với NAN không làm những gì bạn mong đợi. NAN được xử lý như một NULL hợp lý (= không biết). 'float (" nan ") == float (" nan ")' cho 'Sai' (mặc dù có khả năng nó có lẽ nên trả về NAN hoặc None). Tương tự như vậy kỳ quặc với NAN và boolen NULL là đúng trong nhiều ngôn ngữ, bao gồm cả SQL (nơi NULL = NULL là không bao giờ đúng). – user48956

9

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 đó myarray không chứa, numpy.nan, numpy.inf hoặc -numpy.inf giá trị.

numpy.nan sẽ OK với numpy.inf 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) 
+0

Tại sao không giống như 'float ('nan') trong x' không hoạt động? Tôi đã thử nó và python trả về 'False' trong đó' x = [1,2,3, float ('nan')] '. –

+1

@CharlieParker vì hai 'nan' không được coi là bằng nhau. Hãy thử 'float ('nan') == float ('nan')'. – Akavall

+0

thú vị. Tại sao họ không được coi là bình đẳng? –

2

(np.where(np.isnan(A)))[0].shape[0] sẽ lớn hơn 0 nếu A chứa ít nhất một yếu tố của nan, A có thể là một ma trận n x m.

Ví 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" 
Các vấn đề liên quan