You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌套JSON转pandas扁平化DataFrame报KeyError如何解决

问题根因

报错的核心原因是对pd.json_normalize()的展平逻辑理解有误:

  1. 该方法默认只会展开嵌套字典类型的字段,遇到值为列表的字段时,会直接把整个列表作为单元格内容保留,不会自动递归展开列表内部的嵌套结构。
  2. 你使用的DSTC对话数据集是多层嵌套列表结构:最外层是对话列表,每个对话下的turns是轮次列表,每个轮次下的frames是语义帧列表,每个帧下的actions是动作列表。直接调用pd.json_normalize(jsondata)时,turns列存的还是原始列表对象,根本不会生成你写的turns.frames.actions.act、turns.utterance这类点分列名,自然会触发KeyError。
排查&解决方法

按以下步骤操作即可正确展平:

  • 第一步:先验证默认展平的实际列
    先运行print(pd.json_normalize(jsondata).columns.tolist()),你会看到输出里只有dialogue_id、services、turns几个列,turns列的类型是object,存的就是没展开的轮次列表,和你预期的列名完全不一致,这就是报错的直接原因。
  • 第二步:根据你需要的粒度选择展平方式
    json_normalize提供了record_path参数指定要展开的列表路径,meta参数指定要保留的上层字段,多层嵌套建议逐层展开,不容易出错:
    如果你需要把每个对话动作拆成单独一行(最细粒度),用以下代码:
import json
import pandas as pd

with open('./dialogues_001.json', 'r', encoding='utf-8') as f:
    jsondata = json.load(f)

# 第一层:展开对话下的轮次列表,保留对话级字段
turns_df = pd.json_normalize(
    data=jsondata,
    record_path='turns',
    meta=['dialogue_id', 'services'],
    sep='.'
)

# 第二层:展开轮次下的帧列表,保留轮次级字段(比如utterance说话内容)
frames_df = pd.json_normalize(
    data=turns_df.to_dict('records'),
    record_path='frames',
    meta=['dialogue_id', 'services', 'utterance', 'turn_id', 'speaker'],
    sep='.'
)

# 第三层:展开帧下的动作列表,拿到act动作标签
final_df = pd.json_normalize(
    data=frames_df.to_dict('records'),
    record_path='actions',
    meta=['dialogue_id', 'services', 'utterance', 'turn_id', 'speaker'],
    sep='.'
)

# 筛选需要的字段即可,此时act是单独列,不会报KeyError
target_fields = ['dialogue_id', 'services', 'act', 'utterance']
print(final_df[target_fields])

如果你不需要把每个动作拆成单独行,只想把同轮次的所有动作标签合并成一个列表,展平到轮次级即可,不用拆到最细:

import json
import pandas as pd

with open('./dialogues_001.json', 'r', encoding='utf-8') as f:
    jsondata = json.load(f)

# 只展开到轮次级
turns_df = pd.json_normalize(
    data=jsondata,
    record_path='turns',
    meta=['dialogue_id', 'services'],
    sep='.'
)

# 提取每个轮次下所有的act标签,合并为列表
turns_df['turn_acts'] = turns_df['frames'].apply(
    lambda frame_list: [action['act'] for frame in frame_list for action in frame['actions']]
)

# 筛选目标字段
target_fields = ['dialogue_id', 'services', 'turn_acts', 'utterance']
print(turns_df[target_fields])
注意事项
  • 不要凭直觉手写嵌套字段路径,每次调用json_normalize后先打印columns确认实际生成的列名,避免路径写错。
  • 嵌套字典和嵌套列表的展平逻辑完全不同:字典会自动展开为点分列,列表必须通过record_path手动指定展开路径,多层列表嵌套不要试图一步完成展平,逐层处理容错率更高。

内容的提问来源于stack exchange,提问作者sariii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 04:45:57