为什么collections.Counter将numpy.nan视为相等?

7 投票
2 回答
1553 浏览
提问于 2025-04-18 00:03

我对以下行为感到惊讶:

>>> import numpy as np
>>> from collections import Counter
>>> my_list = [1,2,2, np.nan, np.nan]
>>> Counter(my_list)
Counter({nan: 2, 2: 2, 1: 1}) # Counter treats np.nan as equal and 
                              # tells me that I have two of them
>>> np.nan == np.nan          # However, np.nan's are not equal  
False

这到底是怎么回事呢?

当我使用 float('nan') 而不是 np.nan 时,我得到了我预期的结果:

>>> my_list = [1,2,2, float('nan'), float('nan')]
>>> Counter(my_list)
Counter({2: 2, nan: 1, 1: 1, nan: 1}) # two different nan's
>>> float('nan') == float('nan')
False

我使用的是 python 2.7.3numpy 1.8.1

编辑:

如果我这样做:

>>> a = 300
>>> b = 300
>>> a is b
False
>>> Counter([a, b])
Counter({300: 2})

那么,Counter 或任何 Python 的 dict 会认为两个对象 XY 不相同的情况是:

X == Y -> False

and

X is Y -> False

对吗?

2 个回答

5

在Python中,字典(还有它的一个子类Counter)通常是通过比较键的相等性来工作的,也就是说,它们会用==来判断两个键是否相等。但是,它们做了一些优化,假设如果x is y,那么x == y也成立。只有在x is not y的情况下,字典才会回过头来用相等性比较来判断。对于大多数类型来说,x is y意味着x == y是成立的。只有在浮点数的NaN(不是一个数字)和一些特意设计的反例中,这个条件才会被打破。

10

这不是在讨论 numpy.nanfloat("nan") 的区别,而是说你有两个不同的浮点数的“不是数字”(nan)。

>>> np.nan is np.nan
True
>>> float("nan") is float("nan")
False

所以

>>> Counter([1,2,2, np.nan, np.nan])
Counter({nan: 2, 2: 2, 1: 1})
>>> Counter([1,2,2, float("nan"), float("nan")])
Counter({2: 2, nan: 1, 1: 1, nan: 1})

但是

>>> f = float("nan")
>>> Counter([1,2,2, f, f])
Counter({nan: 2, 2: 2, 1: 1})

撰写回答