You need to enable JavaScript to run this app. Python3/pandas≥1.1.4下用json_normalize如何保护嵌套对象不被扁平化
优惠活动
大模型
产品
解决方案
定价
更多

Python3/pandas≥1.1.4下用json_normalize如何保护嵌套对象不被扁平化

实现方案

你查阅官方文档找不到对应方案是正常的,截至目前pandas ≥1.1.4 版本的 json_normalize 仍未内置"嵌套字段保护"类参数,所有现有参数仅能调整扁平化的分隔符、列名前缀、错误处理规则,无法跳过指定嵌套对象的展开逻辑。
但完全可以通过两种无侵入的实现方式达到目标效果,兼容所有指定版本环境:

方案1:字段抽离回填(稳定性最高)

完全基于json_normalize的公开接口逻辑实现,不依赖任何内部实现细节,全版本兼容

  • 执行逻辑:
    • 遍历原始记录,将需要保护的geometry完整嵌套对象从每条记录中抽出、单独存储为独立序列
    • 移除原记录中的geometry字段,对剩余结构执行默认的扁平化逻辑(此时properties等其他嵌套对象会按预期正常拆分)
    • 将抽出的完整geometry对象作为独立列,拼回最终生成的DataFrame
  • 对应实现代码:
import json
import pandas as pd

# 原始API响应解析
res = '''
{
  "results": [
    {
      "geometry": {
        "type": "Polygon",
        "crs": 4326,
        "coordinates": [[[6.0, 49.0],[6.0, 40.0],[7.0, 40.0],[7.0, 49.0],[6.0, 49.0]]]
      },
      "attribute": "layer.metadata",
      "bbox": [6, 40, 7, 49],
      "featureName": "Coniferous_Trees",
      "layerName": "State_Forests",
      "type": "Feature",
      "id": "17",
      "properties": {
        "resolution": "100",
        "Year": "2020",
        "label": "Coniferous"
      }
    }
  ]
}
'''
raw_data = json.loads(res)['results']
protect_field = "geometry"

# 1. 抽取待保护字段
protected_values = []
cleaned_data = []
for item in raw_data:
    protected_values.append(item[protect_field])
    # 拷贝原记录,移除保护字段避免被拆分,不破坏原始数据结构
    temp_item = item.copy()
    del temp_item[protect_field]
    cleaned_data.append(temp_item)

# 2. 执行正常扁平化逻辑
df = pd.json_normalize(cleaned_data)

# 3. 回填保护字段作为独立列
df[protect_field] = protected_values
  • 效果验证:执行后输出的列结构完全匹配预期,geometry列存储完整的原嵌套对象,无拆分:
print(df.columns.tolist())
# 输出:
# ['attribute', 'bbox', 'featureName', 'layerName', 'type', 'id',
#  'properties.resolution', 'properties.Year', 'properties.label', 'geometry']

方案2:非可拆分类包装(写法最简洁)

json_normalize的递归扁平化逻辑仅会展开字典、列表类型的嵌套值,遇到其他类型的实例时会直接作为单元格值保留,不会做拆分:

  • 执行逻辑:
    • 定义一个极简的标记类,用来包装需要保护的对象
    • 遍历原始记录,将需要保护的geometry字典替换成对应标记类的实例,直接执行原生json_normalize即可
    • 后续如果需要获取原对象,直接从包装实例中取出原始内容即可
  • 对应实现代码:
# 极简标记类,仅做类型区分用
class Protected:
    def __init__(self, raw_obj):
        self.value = raw_obj

# 包装待保护的geometry字段
for item in raw_data:
    item["geometry"] = Protected(item["geometry"])

# 直接执行原生扁平化逻辑,无需额外清理
df = pd.json_normalize(raw_data)

# 取出包装层,还原原对象
df["geometry"] = df["geometry"].apply(lambda x: x.value)
  • 注意:这个方法利用了json_normalize的内部类型判断逻辑,虽在≥1.1.4的所有pandas版本中可正常运行,但稳定性弱于方案1,适合快速开发场景使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.30 23:54:03