Python中集合与NaN值的异常行为及差异原因咨询
问题解答
集合的去重逻辑依赖两个核心判断:哈希值相等(hash(a) == hash(b))且相等性判断为真(a == b),而NaN的特殊行为正是源于不同实现对这两个判断的处理差异:
1. {np.nan, np.nan}仅保留一个NaN
Python对所有float类型的NaN(包括numpy的np.nan)做了特殊处理:
- 所有NaN的哈希值是固定且相同的,不管是Python原生
float('nan')还是numpy的np.nan。 - 尽管
np.nan == np.nan返回False,但Python的哈希表(集合、字典)会忽略这个相等性结果,直接将所有NaN视为同一个键,因此重复添加只会保留一个。
2. {(np.nan,), (np.nan,)}仅保留一个元组
元组的哈希值由其元素的哈希值组合而成,因此两个(np.nan,)元组的哈希值相同(因为np.nan的哈希值固定)。
虽然理论上(np.nan,) == (np.nan,)返回False(元组相等性依赖元素逐个比较),但部分Python/numpy版本中,哈希表会沿用NaN的特殊处理逻辑,将这类元组视为相同元素,因此集合只保留一个。
(注:在较新的Python/numpy版本中,这类元组可能会被视为不同元素,集合长度为2,具体取决于版本对元组哈希和NaN的处理细节。)
3. 从Pandas Series取出的NaN创建的元组集合保留两个元组
这是因为Pandas取出的缺失值的哈希行为和numpy原生NaN不同:
- 如果Series使用Pandas的Nullable数据类型(如
Float64、Int64),取出的元素是Pandas自定义的NAType实例,而非numpy的float64。这类实例的哈希值基于对象身份,每个实例的哈希值唯一,因此两个(pd_na,)元组的哈希值不同,集合会视为不同元素。 - 即使Series使用numpy的
float64dtype,部分Pandas版本中,取出的NaN会被包装为Pandas的Float64Scalar对象,这类对象的哈希值同样基于实例身份而非固定值,导致元组哈希值不同,集合无法去重。
内容的提问来源于stack exchange,提问作者cri98li
相关产品推荐
相关产品推荐

