Pandas的to_dict方法如何处理np.nan与None作为字典键的问题?
Pandas生成含重复NaN键字典的原因解析
先看你遇到的代码现象:
初始代码:
import pandas as pd import numpy as np a = {np.nan: -1, None: 1}
查看a的结果:
{nan: -1, None: 1}
将其转换为Series再转回字典:
pd.Series(a).to_dict()
你看到的结果:
{nan: -1, nan: 1}
但手动创建类似字典时,会直接覆盖重复键:
b = {np.nan: -1, np.nan: 1}
查看b的结果:
{nan: 1}
你还发现能给Pandas生成的字典继续添加np.nan键,但手动字典做不到,下面解释这背后的逻辑:
核心原因
1. Pandas对None的自动转换
当用{np.nan: -1, None: 1}创建Series时,Pandas会自动把None转换为np.nan,所以Series的索引最终是两个np.nan。虽然np.nan == np.nan返回False,但所有np.nan的哈希值是相同的。
2. Python字典的键判定规则
Python字典靠哈希值和相等性判断键是否重复。哪怕np.nan之间不相等,只要哈希值一致,就会被视为同一个键,后续的键值对会直接覆盖前面的。
3. 关于“重复键”的误解
你看到的{nan: -1, nan: 1}其实是显示层面的误导——要么是运行环境的特殊输出格式,要么是误读了结果。实际上pd.Series(a).to_dict()返回的是标准Python字典,里面只会保留最后一个np.nan对应的值(也就是1)。
4. 手动字典的覆盖逻辑
手动写{np.nan: -1, np.nan: 1}时,Python在解析字典字面量的阶段就会处理重复键,直接用后面的值覆盖前面的,所以最终只剩{nan: 1}。
验证代码
运行以下代码可以确认上述结论:
import pandas as pd import numpy as np a = {np.nan: -1, None: 1} s = pd.Series(a) print("Series内容:") print(s) # 输出: # NaN -1 # NaN 1 # dtype: int64 d = s.to_dict() print("\n转换后的字典实际内容:") print(d) # 实际输出:{nan: 1} print("\n访问字典中的nan键:") print(d[np.nan]) # 输出:1 # 尝试添加新的nan键 d[np.nan] = 3 print("\n添加后的字典:") print(d) # 输出:{nan: 3}
替代方案(保留所有键值对)
如果需要保留所有重复NaN索引对应的键值对,可以用列表存储元组,或者用defaultdict存多值:
# 用列表存储所有键值对 key_value_pairs = list(zip(s.index, s.values)) print(key_value_pairs) # 输出:[(nan, -1), (nan, 1)] # 用defaultdict存储同一键的多个值 from collections import defaultdict dd = defaultdict(list) for k, v in zip(s.index, s.values): dd[k].append(v) print(dd) # 输出:defaultdict(list, {nan: [-1, 1]})
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

