Pandas合理展开嵌套JSON数据的全过程

 更新时间:2026年03月26日 09:26:15   作者:白酒永远的神  
在数据分析实践中,我们经常需要处理来自 REST API、日志系统或 NoSQL 数据库(如 MongoDB)的嵌套 JSON 数据,这类数据结构灵活,但往往包含多层嵌套,本文将通过一个典型三层嵌套 JSON 示例,系统讲解如何合理展开嵌套数据,需要的朋友可以参考下

在数据分析实践中,我们经常需要处理来自 REST API、日志系统或 NoSQL 数据库(如 MongoDB)的嵌套 JSON 数据。这类数据结构灵活,但往往包含多层嵌套,例如用户信息中嵌套地址,同时关联多个订单记录。直接将这样的数据导入 pandas 通常会得到一列包含字典或列表的“半成品” DataFrame,无法直接用于分析。

虽然 pandas 提供了 pd.json_normalize() 等工具来展开嵌套结构,但在处理一对多关系(如一个用户对应多个订单)时,容易产生大量重复字段,导致内存膨胀和计算效率下降。本文将通过一个典型三层嵌套 JSON 示例,系统讲解如何合理展开嵌套数据,并根据分析目标选择最优策略,避免不必要的冗余。

一、问题示例:三层嵌套 JSON

考虑如下数据结构:

data = [
    {
        "user_id": 1,
        "name": "Alice",
        "profile": {
            "age": 30,
            "address": {
                "city": "Beijing",
                "country": "China"
            }
        },
        "orders": [
            {"order_id": "O1", "amount": 100},
            {"order_id": "O2", "amount": 200}
        ]
    },
    {
        "user_id": 2,
        "name": "Bob",
        "profile": {
            "age": 25,
            "address": {
                "city": "Shanghai",
                "country": "China"
            }
        },
        "orders": [
            {"order_id": "O3", "amount": 150}
        ]
    }
]

目标是将每个订单作为一行,同时附带用户的基本信息,形成如下表格:

user_idnameagecitycountryorder_idamount
1Alice30BeijingChinaO1100
1Alice30BeijingChinaO2200
2Bob25ShanghaiChinaO3150

乍看之下,这似乎是一个简单的扁平化任务。但若某个用户有成百上千个订单,其基本信息将在每一行重复出现,造成显著的数据冗余。

二、基础方法:使用json_normalize+explode

pandas 的 pd.json_normalize() 是处理嵌套 JSON 的核心工具。它能自动将 a.b.c 形式的路径展开为列名:

import pandas as pd
df = pd.json_normalize(data)
# 列包括:user_id, name, profile.age, profile.address.city, ...

然而,orders 字段是一个字典列表,仍以列表形式存在。需进一步展开:

# 保留非 orders 字段
df_base = df.drop(columns=['orders'])

# 展开 orders
df_orders = df[['user_id', 'orders']].explode('orders').reset_index(drop=True)
df_orders_flat = pd.json_normalize(df_orders['orders'])

# 合并
result = pd.concat([
    df_base.loc[df_base.index.repeat(df['orders'].apply(len))].reset_index(drop=True),
    df_orders_flat
], axis=1)

此方法可得到所需宽表,但如前所述,用户信息被重复复制。若订单数量庞大,这种冗余将带来以下问题:

  • 内存占用急剧增加
  • 后续聚合或分组操作效率降低
  • 存储成本上升(尤其在持久化为 CSV/Parquet 时)

因此,是否展开应取决于分析目标,而非技术便利性。

三、根据分析场景选择策略

场景 1:以订单为分析单元(如计算每单金额、地域分布)

此时需要将用户属性“附着”到订单上,展开是合理的。但可通过以下方式优化:

  • 使用 category 类型压缩重复字符串
for col in ['name', 'city', 'country']:
    result[col] = result[col].astype('category')

这可将内存占用降低 50% 以上,尤其适用于高基数分类变量。

  • 仅保留必要字段:避免将整个用户对象展开,只提取分析所需的字段(如 city 而非完整 address)。

场景 2:以用户为分析单元(如统计用户总数、平均年龄)

此时不应展开订单。更优做法是构建两个独立表,模仿星型模型:

用户表(users)

user_idnameagecitycountry

订单表(orders)

user_idorder_idamount

实现方式:

# 用户表
users = pd.json_normalize(data)[[
    'user_id', 'name', 'profile.age',
    'profile.address.city', 'profile.address.country'
]]
users.columns = ['user_id', 'name', 'age', 'city', 'country']

# 订单表
orders_list = []
for user in data:
    for order in user['orders']:
        orders_list.append({
            'user_id': user['user_id'],
            'order_id': order['order_id'],
            'amount': order['amount']
        })
orders = pd.DataFrame(orders_list)

后续分析时按需关联:

# 例如:计算各城市订单总额
merged = orders.merge(users[['user_id', 'city']], on='user_id')
summary = merged.groupby('city')['amount'].sum()

这种方式避免了冗余,且便于维护和扩展。

场景 3:数据规模极大(百万级以上)

当数据量超出单机内存限制时,建议:

  • 使用 PolarsDask:它们对嵌套结构支持更好,且支持惰性计算。
  • 采用 列式存储格式(如 Parquet) 并按 user_id 分区,减少 I/O 开销。
  • 在 ETL 阶段保留原始嵌套结构,在查询时动态展开所需部分。

四、不要为了“整齐”而盲目展开

一个常见误区是认为“所有数据都必须变成宽表才便于分析”。实际上,展开是一种分析前的数据准备手段,不是存储规范

在实际项目中,推荐的做法是:

  1. ETL 阶段:保留原始结构或拆分为规范化表;
  2. 分析阶段:根据具体问题临时展开或 join;
  3. 避免持久化高度冗余的宽表,除非有明确的 BI 报表需求。

此外,手写循环解析虽直观,但难以处理缺失字段、类型不一致等问题,且不可复用。相比之下,json_normalize + explode 的组合更具健壮性和扩展性。

五、总结

处理嵌套 JSON 时,pandas 提供了强大而灵活的工具链,但关键在于理解数据语义与分析目标之间的关系

  • 若分析单位是“子记录”(如订单、日志事件),可接受适度冗余,但应优化存储类型;
  • 若分析单位是“主实体”(如用户、设备),应保持数据规范化,通过关联获取细节;
  • 对于超大规模数据,考虑更现代的分析引擎(如 Polars)或分布式方案。

最终,高效的数据处理不在于“能否展开”,而在于“何时展开、展开多少、如何管理冗余”。掌握这一思维,才能在复杂数据结构面前游刃有余。

以上就是Pandas合理展开嵌套JSON数据的全过程的详细内容,更多关于Pandas展开嵌套JSON数据的资料请关注脚本之家其它相关文章!

相关文章

  • Iconfont(矢量图标)+iconmoon(图标svg互转)配合javascript实现社交分享系统

    Iconfont(矢量图标)+iconmoon(图标svg互转)配合javascript实现社交分享系统

    这篇文章主要介绍了Iconfont(矢量图标)+iconmoon(图标svg互转)配合javascript实现社交分享系统,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • Python实现获取本机网卡的MAC地址,IP地址和路由表

    Python实现获取本机网卡的MAC地址,IP地址和路由表

    本文主要为大家详细介绍了如何在Windows和Mac系统下获取本机MAC地址和IP地址的方法,以及如何使用ARP协议获取局域网内所有计算机的IP地址与MAC地址,感兴趣的小伙伴可以了解下
    2026-05-05
  • Python绘制K线图之可视化神器pyecharts的使用

    Python绘制K线图之可视化神器pyecharts的使用

    这篇文章主要介绍了Python绘制K线图之可视化神器pyecharts的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • Python 中 Meta Classes详解

    Python 中 Meta Classes详解

    首先,在认识metaclass之前,你需要认识下python中的class。python中class的奇怪特性借鉴了smalltalk语言。大多数语言中,classes仅仅是用于描述怎样创建一个对象的代码端。在某种程度上说,python中的class也是这样的。
    2016-02-02
  • Django中ORM的基本使用教程

    Django中ORM的基本使用教程

    这篇文章主要给大家介绍了关于Django中ORM基本使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • 使用Python快速搭建文件传输服务的方法

    使用Python快速搭建文件传输服务的方法

    这篇文章主要介绍了使用Python快速搭建一个文件传输服务,这样任何一个人都能打开浏览器把他电脑上的文件传给我了,本文给大家介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • Python 安装 virturalenv 虚拟环境的教程详解

    Python 安装 virturalenv 虚拟环境的教程详解

    这篇文章主要介绍了Python 安装 virturalenv 虚拟环境的教程,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-02-02
  • Python正则表达式re模块讲解以及其案例举例

    Python正则表达式re模块讲解以及其案例举例

    Python中re模块主要功能是通过正则表达式是用来匹配处理字符串的 ,下面这篇文章主要给大家介绍了关于Python正则表达式re模块讲解以及其案例举例的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • Python中set方法的使用教程详解

    Python中set方法的使用教程详解

    在Python中,set是一种集合数据类型,表示一个无序且不重复的集合。本文主要为大家详细介绍了Python中set方法的使用,需要的可以参考一下
    2023-04-04
  • 关于Python如何避免循环导入问题详解

    关于Python如何避免循环导入问题详解

    在大型的Python工程中,由于架构设计不当,可能会出现模块间相互引用的情况。下面这篇文章主要给大家介绍了关于如何避免Python的循环导入问题的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-09-09

最新评论