Определить, содержит ли массив NumPy хотя бы одно нечисловое значение?

StackOverflow https://stackoverflow.com/questions/911871

  •  06-09-2019
  •  | 
  •  

Вопрос

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

Очевидный способ решить эту проблему - написать рекурсивную функцию, которая перебирает каждый итерабельный объект в массиве до тех пор, пока не найдет неитерабельный.Это будет применять 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
Это было полезно?

Решение

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

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.конечный

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)

С помощью 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

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

(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"

Пффф!Микросекунды!Никогда не решайте проблему за микросекунды, которая может быть решена за наносекунды.

Обратите внимание, что принятый ответ:

  • выполняет итерацию по всем данным, независимо от того, найден ли nan
  • создает временный массив размером N, который является избыточным.

Лучшим решением является немедленное возвращение True при нахождении 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)

и работает для 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 порядка или величину (в некоторых случаях).Не слишком убого для простой аннотации.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top