Python\Numpy: 比较包含NAN的数组

6 投票
3 回答
5051 浏览
提问于 2025-04-18 07:19

为什么下面这两个列表不相等呢?

a = [1.0, np.NAN] 
b = np.append(np.array(1.0), [np.NAN]).tolist()

我用以下方法来检查它们是否相同。

((a == b) | (np.isnan(a) & np.isnan(b))).all(), np.in1d(a,b)

使用 np.in1d(a, b) 这个方法时,发现 np.NAN 的值不相等,但我不太明白这是为什么。有没有人能帮我解释一下这个问题?

3 个回答

0

在Python(还有numpy库)中,NaN是按照IEEE 754标准来实现的(你可以查看这个链接了解更多:http://en.wikipedia.org/wiki/NaN)。简单来说,NaN被定义为“无法排序的”。这意味着在比较操作中,比如用<>==等来判断时,NaN永远不会返回True。为了判断一个值是否是NaN,numpy和内置的math模块提供了isnan这个函数。

8

NaN值是“不是一个数字”的意思,它们永远不会被认为是相等的。也就是说,测试 NaN==NaN 的结果总是 False,这是因为 NaN 的定义就是这样。

所以 [1.0, NaN] == [1.0, NaN] 的结果也是 False。实际上,一旦在任何列表中出现了 NaN,它就无法与任何其他列表进行相等比较,甚至连它自己也不行。

如果你想检查一个变量是否是 NaN,可以在 numpy 中使用 numpy.isnan() 这个函数。我没有看到有什么简单的方法可以实现你想要的比较,除了通过“手动”使用循环来遍历列表。

考虑以下代码:

import math
import numpy as np

def nan_eq(a, b):
    for i,j in zip(a,b):
        if i!=j and not (math.isnan(i) and math.isnan(j)):
            return False
    return True

a=[1.0, float('nan')]
b=[1.0, float('nan')]

print( float('nan')==float('nan') )
print( a==a )
print( a==b )
print( nan_eq(a,a) )

这段代码会打印:

False
True
False
True

测试 a==a 成功是因为,Python认为对同一个对象的引用是相等的,这种想法优先于 a==b 所需的逐元素比较的结果。

5

因为 ab 是列表,所以 a == b 不会返回一个数组,所以你用的那种类似于numpy的逻辑是行不通的:

>>> a == b
False

你提到的这个命令只有在它们是 数组 的时候才有效:

>>> a,b = np.asarray(a), np.asarray(b)
>>> a == b
array([ True, False], dtype=bool)
>>> (a == b) | (np.isnan(a) & np.isnan(b))
array([ True,  True], dtype=bool)
>>> ((a == b) | (np.isnan(a) & np.isnan(b))).all()
True

这个命令应该可以用来比较两个数组(要么它们相等,要么它们都是NaN)。

撰写回答