应使用 pandas.json_normalize() 扁平化多层嵌套字典,需正确指定 record_path(如 ["data", "items"])、meta 提取父级字段,并配合 explode、fillna、sep="_" 等处理数组、空值、点号命名等问题。

用 pandas.json_normalize() 处理多层嵌套字典
直接用 pd.DataFrame() 构造嵌套字典会把整个子字典塞进一个单元格,根本没法当报表用。真正该用的是 pandas.json_normalize() —— 它专为扁平化嵌套结构设计,比手写递归或 pd.json_normalize() 的旧别名更可靠(注意:不是 pd.io.json.json_normalize,那个已弃用)。
常见错误是传入单个字典却没指定 record_path,结果只展开一层就停了。如果嵌套在 "data" 键下,得显式写 json_normalize(data, record_path="data");如果还有二级嵌套如 "items",就得用 record_path=["data", "items"]。
实操建议:
- 先用
print(type(your_data))和print(list(your_data.keys()))确认顶层结构,别盲目传参 - 遇到列表内嵌字典(如
[{"id":1,"tags":["a","b"]}]),json_normalize()默认不展开数组字段,需配合meta参数提取父级字段,再用explode("tags")拆开 - 若字段名含点号(如
"user.name"),sep="."会保留层级,但导出 Excel 时可能被当成小数——建议用sep="_"避坑
处理不规则嵌套:缺失键、混合类型、空值
真实数据里常有某些记录缺 "address",另一些的 "phone" 是 None 或空字符串,json_normalize() 默认用 None 填充缺失键,但若某字段在部分记录里是字典、另一些是字符串,就会触发 TypeError: unhashable type: 'dict'。
立即学习“Python免费学习笔记(深入)”;
这时候不能硬调用,得预处理:
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- 用
pd.json_normalize([clean_record(d) for d in raw_list]),其中clean_record()统一将非字典字段转为空字典(如if not isinstance(d.get("profile"), dict): d["profile"] = {}) - 对可能为
None的嵌套路径,加errors="ignore"参数,跳过解析失败项(慎用,会静默丢数据) - 导出前用
df.fillna("")或df.replace({np.nan: "", None: ""}),避免 Excel 里显示nan
生成明细报表的关键列操作
“明细报表”意味着每行对应一个原子业务实体(比如一笔订单里的一个商品),不是按用户聚合。所以重点不在 groupby,而在精准拆解和补全上下文。
典型场景:API 返回的订单数据中,"order_id" 在外层,"items" 是列表,每个 item 有 "sku" 和 "qty"。要得到“每 sku 一行 + 带上 order_id”,步骤是:
- 先
json_normalize(data, record_path=["items"], meta=["order_id", "created_at"], errors="raise") - 如果
"items"本身是空列表,json_normalize()会返回空 DataFrame —— 得提前判断if not data.get("items"):并构造空 schema - 用
df.rename(columns={"sku": "product_sku"})统一命名,别依赖原始 key,接口变一次就崩 - 导出时用
df.to_excel("report.xlsx", index=False),否则第一列多出无意义的 row number
性能与内存:大嵌套数据别一次性全读
当原始字典超 10MB 或含上万条嵌套记录时,json_normalize() 会吃光内存。它内部把所有路径展开成新列,列数爆炸(比如 5 层嵌套 × 20 字段 = 百级列名)。
更稳的做法:
- 用
orjson.loads()替代json.loads()加速解析(需先pip install orjson) - 分块处理:把大列表切片,例如
for i in range(0, len(big_list), 500): chunk = big_list[i:i+500]; df_chunk = json_normalize(chunk, ...); all_dfs.append(df_chunk) - 不用
meta提取过多父级字段——只留报表必需的,比如只要"order_id",别把整个"customer"字典都设为meta
嵌套越深,json_normalize() 的路径表达式越容易写错;宁可多拆一步用 apply() + pd.Series 手动展平,也别让路径参数变成谜题。

















