2009-05-26 2 views
48

Мне нужно написать функцию, которая будет определять, содержит ли вход хотя бы одно значение, которое не является числовым. Если обнаружено нечисловое значение, я подниму ошибку (потому что вычисление должно возвращать только числовое значение). Количество измерений входного массива неизвестно заранее - функция должна давать правильное значение независимо от ndim. В качестве дополнительного усложнения вход может быть одним поплавком или numpy.float64 или даже чем-то странным, как нулевой размерный массив.Определить, содержит ли массив NumPy хотя бы одно нечисловое значение?

Очевидным способом решения этой проблемы является запись рекурсивной функции, которая выполняет итерацию по каждому истребимому объекту в массиве до тех пор, пока не найдет не итерабельность. Он будет применять функцию numpy.isnan() для каждого объекта без итераций. Если найдено хотя бы одно нечисловое значение, функция немедленно вернет False. В противном случае, если все значения в iterable являются числовыми, он в конечном итоге вернет 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' выглядит подозрительно:«Возвращает ложь, если по крайней мере один нечисловое значение существует». Я бы ожидал, что 'contains_nan' вернет' True', если массив содержит NaN. –

+0

Что касается входов, таких как 'array (['None', 'None'], dtype = object)'? Должен ли такой ввод просто поднять исключение? –

+0

НЕ используйте 'float ('nan') в x'. Это не работает. –

ответ

78

Это должно быть быстрее, чем итерация и будет работать независимо от формы.

numpy.isnan(myarray).any() 

Edit: 30x быстрее:

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 
+0

с numpy 1.7 версия flatten() только в два раза быстрее первой –

+0

Почему в x' не работает что-то вроде 'float ('nan')? Я попробовал, и python возвращает 'False', где' x = [1,2,3, float ('nan')] '. –

+1

@CharlieParker по той же причине, почему float ('nan') == float ('nan') вернет False. NaN не равен NaN. Здесь больше информации: http://stackoverflow.com/questions/10034149/why-is-nan-not-equal-to-nan – Muppet

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 

Обработка ран в сопоставлениях не была согласованной в более ранних версиях.

+0

Почему в x' не работает что-то вроде 'float ('nan')? Я попробовал, и python возвращает 'False', где' x = [1,2,3, float ('nan')] '. –

+0

@CharlieParker ... потому что сравнение с NAN не делает то, что вы ожидаете. NAN обрабатывается как логический NULL (= не знаю). 'float (" nan ") == float (" nan ")' дает 'False' (хотя возможно, вероятно, он вернет NAN или None). Аналогично странность с NAN и boolen NULL истинна на многих языках, включая SQL (где NULL = NULL никогда не является истинным). – user48956

9

Если бесконечность является возможным значением, я хотел бы использовать numpy.isfinite

numpy.isfinite(myarray).all() 

Если указанное выше имеет значение True, то myarray не содержит, numpy.nan, numpy.inf или -numpy.inf значения.

numpy.nan будет ОК с 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) 
+0

Почему не что-то вроде 'float ('nan') в x' не работает? Я попробовал, и python возвращает 'False', где' x = [1,2,3, float ('nan')] '. –

+1

@CharlieParker, потому что два 'nan' не считаются равными друг другу. Попробуйте 'float ('nan') == float ('nan')'. – Akavall

+0

интересный. Почему они не считаются равными? –

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" 
Смежные вопросы