检测NumPy数组是否包含至少一个非数值?


103

我需要编写一个函数来检测输入是否包含至少一个非数字值。如果找到一个非数字值,我将引发一个错误(因为该计算应仅返回一个数字值)。预先不知道输入数组的维数-无论ndim如何,函数都应给出正确的值。更为复杂的是,输入可能是单个浮点数,numpy.float64或者甚至是零维数组之类的奇数。

解决此问题的明显方法是编写一个递归函数,该函数对数组中的每个可迭代对象进行迭代,直到找到一个非iterabe。它将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看起来很可疑:“如果至少存在一个非数字值,则返回false”。如果该数组包含NaN,我会期望contains_nan返回True
塞缪尔·塔迪厄

诸如此类的输入array(['None', 'None'], dtype=object)呢?这样的输入是否应该引发例外?
FinnÅrupNielsen

不要使用 float('nan') in x。这是行不通的。
查理·帕克

Answers:


182

这应该比迭代更快,并且无论形状如何都可以工作。

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时,flatten()版本的速度仅是第一个版本的两倍
Christian Geier

为什么有些东西float('nan') in x不起作用?我试了一下,python返回Falsewhere x = [1,2,3,float('nan')]
查理·帕克

1
@CharlieParker为何float('nan')== float('nan')返回False的原因相同。NaN不等于NaN。这里的更多信息:stackoverflow.com/questions/10034149/…–
Muppet

1
@mab:这是因为调用numpy.anygenexp只会返回genexp;您实际上并没有进行您认为自己的计算。切勿调用numpy.anygenexp。
user2357112支持Monica's

在实际调试情况下,我也建议在看np.isfinite,而不是np.isnan检测数值溢出,不稳定等
本·乌斯曼

18

如果无穷是一个可能的值,我将使用numpy.isfinite

numpy.isfinite(myarray).all()

如果以上计算结果为True,则不myarray包含numpy.nannumpy.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)

为什么有些东西float('nan') in x不起作用?我试了一下,python返回Falsewhere x = [1,2,3,float('nan')]
查理·帕克

1
@CharlieParker,因为两个nan不被视为彼此相等。尝试float('nan') == float('nan')
Akavall '16

有趣。为什么不认为它们相等?
查理·帕克

1
@CharlieParker,我想我不能在这里给出一个很好的答案。也许这是你在找什么:stackoverflow.com/questions/1565164/...
Akavall

4

ff!微秒!永远不要在几微秒内解决可以在十亿分之一秒内解决的问题。

注意接受的答案:

  • 遍历整个数据,无论是否找到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

比较中对Nans的处理在早期版本中不一致。


为什么有些东西float('nan') in x不起作用?我试了一下,python返回Falsewhere x = [1,2,3,float('nan')]
查理·帕克

@CharlieParker ...因为与NAN的比较没有达到您的期望。NAN被视为逻辑NULL(=不知道)。 float("nan")==float("nan")给定False(尽管可能应该返回NAN或None)。类似地,NAN和布尔NULL的奇数在许多语言中都适用,包括SQL(其中NULL = NULL从未为true)。
user48956 '17

2

(np.where(np.isnan(A)))[0].shape[0]将大于0如果A含有的至少一种元素nanA可以是一个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"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.