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

Aka*_*all 7 python numpy

我对以下行为感到惊讶:

>>> 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
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

当我使用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
Run Code Online (Sandbox Code Playgroud)

我正在使用python 2.7.3numpy 1.8.1.

编辑:

如果我做:

>>> a = 300
>>> b = 300
>>> a is b
False
>>> Counter([a, b])
Counter({300: 2})
Run Code Online (Sandbox Code Playgroud)

所以,Counter或者任何python dict考虑两个对象X,Y如果:

X == Y -> False

and

X is Y -> False
Run Code Online (Sandbox Code Playgroud)

正确?

DSM*_*DSM 8

这不是关于numpy.nanvs. float("nan"),而是你有两个独立的浮点数.

>>> np.nan is np.nan
True
>>> float("nan") is float("nan")
False
Run Code Online (Sandbox Code Playgroud)

所以

>>> 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})
Run Code Online (Sandbox Code Playgroud)

>>> f = float("nan")
>>> Counter([1,2,2, f, f])
Counter({nan: 2, 2: 2, 1: 1})
Run Code Online (Sandbox Code Playgroud)


Rob*_*ern 5

Python 字典(以及扩展的Counter子类)通常基于==键的相等比较来工作。他们做了一个优化,假设 if x is ythen x == y。只有这样,x is not y字典才会退回到平等比较。对于大多数类型,x is y意味着x == y. 基本上只有浮点 NaN 和故意设计的反例才能打破这个条件。