比较含有NaN的numpy数组

sar*_*ele 52 python numpy

对于我的unittest,我想检查两个数组是否相同.减少的例子:

a = np.array([1, 2, np.NaN])
b = np.array([1, 2, np.NaN])
if np.all(a==b):
    print 'arrays are equal'
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为nan!= nan.什么是最好的方法?

提前致谢.

sen*_*rle 37

我不确定这是最好的方法,但这是一种方式:

>>> ((a == b) | (numpy.isnan(a) & numpy.isnan(b))).all()
True
Run Code Online (Sandbox Code Playgroud)


Ava*_*ris 33

或者您可以使用numpy.testing.assert_equalnumpy.testing.assert_array_equal使用try/except:

In : import numpy as np

In : def nan_equal(a,b):
...:     try:
...:         np.testing.assert_equal(a,b)
...:     except AssertionError:
...:         return False
...:     return True

In : a=np.array([1, 2, np.NaN])

In : b=np.array([1, 2, np.NaN])

In : nan_equal(a,b)
Out: True

In : a=np.array([1, 2, np.NaN])

In : b=np.array([3, 2, np.NaN])

In : nan_equal(a,b)
Out: False
Run Code Online (Sandbox Code Playgroud)

编辑

由于您使用它进行单元测试,裸assert(而不是将其包裹起来True/False)可能更自然.

  • 请注意,这个解决方案有效,因为`numpy.testing.assert_*`不遵循python`assert`的相同语义.在普通的Python`AssertionError`中,如果`__debug__为True,则引发异常,即如果脚本未经优化运行(没有-O标志),请参阅[docs](http://docs.python.org/3.3/reference) /simple_stmts.html#grammar-token-assert_stmt).出于这个原因,我强烈建议不要将'AssertionErrors`包装成流量控制.当然,由于我们在测试套件中,最好的解决方案是单独留下numpy.testing.assert. (4认同)

Lui*_*eno 25

最简单的方法是使用numpy.allclose()方法,它允许在具有nan值时指定行为.然后您的示例将如下所示:

a = np.array([1, 2, np.nan])
b = np.array([1, 2, np.nan])

if np.allclose(a, b, equal_nan=True):
    print 'arrays are equal'
Run Code Online (Sandbox Code Playgroud)

然后arrays are equal将打印.

您可以在这里找到相关文档

  • +1 因为您的解决方案不会重新发明轮子。但是,这只适用于类似数字的项目。否则,您会收到令人讨厌的 `TypeError: ufunc 'isfinite' not supported for the input types,并且无法根据转换规则 ''safe'' 将输入安全地强制转换为任何受支持的类型 (2认同)
  • 正如指向稍后答案的指针:/sf/answers/4109637731/。添加 `rtol=0, atol=0` 以避免它认为接近值相等的问题(如 @senderle 提到的)。所以:`np.allclose(a, b, equal_nan=True, rtol=0, atol=0)`。 (2认同)

fly*_*man 18

numpy函数array_equal通过1.19中添加的参数完美符合问题的要求equal_nan。该示例如下所示:

a = np.array([1, 2, np.NaN])
b = np.array([1, 2, np.NaN])
assert np.array_equal(a, b, equal_nan=True)
Run Code Online (Sandbox Code Playgroud)

但请注意,如果元素属于 dtype ,则此方法将不起作用object。不确定这是否是一个错误


Jos*_*del 9

你可以使用numpy蒙面数组,掩盖NaN值,然后使用numpy.ma.allnumpy.ma.allclose:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.ma.all.html

http://docs.scipy.org/doc/numpy/reference/generated/numpy.ma.allclose.html

例如:

a=np.array([1, 2, np.NaN])
b=np.array([1, 2, np.NaN])
np.ma.all(np.ma.masked_invalid(a) == np.ma.masked_invalid(b)) #True
Run Code Online (Sandbox Code Playgroud)

  • 我测试了`a = np.array([1,2,np.NaN])`和`b = np.array([1,np.NaN,2])`,它们显然是不相等的和`np.ma .all(np.ma.masked_invalid(a)== np.ma.masked_invalid(b))`仍然返回True,所以如果你使用这个方法,请注意这一点. (3认同)
  • 谢谢你让我意识到使用蒙面数组.不过我更喜欢Avaris的解决方案. (2认同)

Ale*_*uat 7

只是为了完成@Luis Albert Centeno 的回答,您可能更愿意使用:

np.allclose(a, b, rtol=0, atol=0, equal_nan=True)
Run Code Online (Sandbox Code Playgroud)

rtolatol控制平等测试的容忍度。简而言之,allclose()返回:

all(abs(a - b) <= atol + rtol * abs(b))
Run Code Online (Sandbox Code Playgroud)

默认情况下,它们未设置为 0,因此True如果您的数字接近但不完全相等,该函数可能会返回。


PS:“我想检查两个数组是否相同”>> 实际上,您正在寻找相等而不是identity。它们在 Python 中并不相同,我认为每个人都理解差异以便共享相同的词典会更好。( https://www.blog.pythonlibrary.org/2017/02/28/python-101-equality-vs-identity/ )

您将通过关键字测试身份is

a is b
Run Code Online (Sandbox Code Playgroud)


Mat*_*ujo 5

当我使用以上答案时:

 ((a == b) | (numpy.isnan(a) & numpy.isnan(b))).all()
Run Code Online (Sandbox Code Playgroud)

当评估字符串列表时,它给了我一些错误。

这是更通用的类型:

def EQUAL(a,b):
    return ((a == b) | ((a != a) & (b != b)))
Run Code Online (Sandbox Code Playgroud)