最稳妥方式是用 pandas.json_normalize 处理单列字典,它能自动对齐缺失键并填 NaN;嵌套字典可用 sep='.' 展开,输入须为 list 或 Series;遇 TypeError 需先清洗非字典类型;字段含点号可用 sep='_' 避免冲突;大数据量时可改用 str.get 或 polars 提速。

直接用 pandas.json_normalize 处理单列字典
如果目标列里每个元素都是一个字典(比如 df['info'] 是 [{'a': 1, 'b': 2}, {'a': 3, 'c': 4}]),最稳妥的方式是用 pandas.json_normalize,而不是 pd.DataFrame(df['col'].tolist())——后者在字典键不一致时会丢数据或报错。
实操建议:
-
json_normalize能自动对齐缺失键,空缺处填NaN,比手动构造 DataFrame 更健壮 - 若字典嵌套(如
{'user': {'name': 'Alice', 'id': 101}}),加参数sep='.'可展开成user.name、user.id - 注意:输入必须是 list 或 Series,不能直接传入 DataFrame 列的
.values(可能触发ValueError: Expected object or value) - 示例:
from pandas import json_normalize<br>expanded = json_normalize(df['info'])
遇到 TypeError: unhashable type: 'dict' 怎么办
这通常发生在你试图用 df['col'].apply(pd.Series) 或直接 pd.DataFrame(df['col']),而该列里混有 None、NaN 或非字典类型(比如字符串、列表)。
解决路径:
立即学习“Python免费学习笔记(深入)”;
- 先清洗:用
df['col'].apply(type).unique()看实际类型分布 - 过滤掉非字典项:
mask = df['col'].apply(lambda x: isinstance(x, dict)),再只对df[mask]['col']操作 - 把
None统一转为空字典:df['col'] = df['col'].apply(lambda x: x if isinstance(x, dict) else {}) - 避免用
pd.Series直接展开,它对None敏感;优先选json_normalize
字段名重复或含点号(.)导致列名冲突
json_normalize 默认用 . 连接嵌套键,比如 {'meta': {'status': 'ok', 'code': 200}} 展开后列名是 meta.status、meta.code。但如果你后续要做 df.groupby('meta.status'),点号会让语法出错(Python 解析器认为是属性访问)。
处理方式:
- 用
sep='_'替换分隔符:json_normalize(df['info'], sep='_')→ 得到meta_status - 或者事后重命名:
expanded.columns = [c.replace('.', '_') for c in expanded.columns] - 更彻底的做法:提前用
record_path和meta参数指定展开层级,避免无谓嵌套
性能差?大数据量下 json_normalize 卡顿
当该列有几十万行字典时,json_normalize 会比纯 Python 循环还慢——因为它内部做了大量类型推断和空值对齐。
提速方案:
- 确认是否真需要全量展开:有时只需提取几个关键键,用
df['col'].str.get('key_name')更快(前提是列是object类型且内容确实是字典) - 若必须全展开,先用
ast.literal_eval预处理字符串(有些字典存的是 JSON 字符串而非 dict 对象) - 极端情况可改用
polars:pl.from_pandas(df).with_columns(pl.col('info').struct.unnest()),尤其适合嵌套结构固定的情况
真正麻烦的不是怎么展开,而是字典结构是否稳定——键名动态变化、深层嵌套、混合类型,这些才是后期维护的硬伤。


















