Pandas合理展開嵌套JSON數(shù)據(jù)的全過程
在數(shù)據(jù)分析實踐中,我們經(jīng)常需要處理來自 REST API、日志系統(tǒng)或 NoSQL 數(shù)據(jù)庫(如 MongoDB)的嵌套 JSON 數(shù)據(jù)。這類數(shù)據(jù)結構靈活,但往往包含多層嵌套,例如用戶信息中嵌套地址,同時關聯(lián)多個訂單記錄。直接將這樣的數(shù)據(jù)導入 pandas 通常會得到一列包含字典或列表的“半成品” DataFrame,無法直接用于分析。
雖然 pandas 提供了 pd.json_normalize() 等工具來展開嵌套結構,但在處理一對多關系(如一個用戶對應多個訂單)時,容易產(chǎn)生大量重復字段,導致內(nèi)存膨脹和計算效率下降。本文將通過一個典型三層嵌套 JSON 示例,系統(tǒng)講解如何合理展開嵌套數(shù)據(jù),并根據(jù)分析目標選擇最優(yōu)策略,避免不必要的冗余。
一、問題示例:三層嵌套 JSON
考慮如下數(shù)據(jù)結構:
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_id | name | age | city | country | order_id | amount |
|---|---|---|---|---|---|---|
| 1 | Alice | 30 | Beijing | China | O1 | 100 |
| 1 | Alice | 30 | Beijing | China | O2 | 200 |
| 2 | Bob | 25 | Shanghai | China | O3 | 150 |
乍看之下,這似乎是一個簡單的扁平化任務。但若某個用戶有成百上千個訂單,其基本信息將在每一行重復出現(xiàn),造成顯著的數(shù)據(jù)冗余。
二、基礎方法:使用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)
此方法可得到所需寬表,但如前所述,用戶信息被重復復制。若訂單數(shù)量龐大,這種冗余將帶來以下問題:
- 內(nèi)存占用急劇增加
- 后續(xù)聚合或分組操作效率降低
- 存儲成本上升(尤其在持久化為 CSV/Parquet 時)
因此,是否展開應取決于分析目標,而非技術便利性。
三、根據(jù)分析場景選擇策略
場景 1:以訂單為分析單元(如計算每單金額、地域分布)
此時需要將用戶屬性“附著”到訂單上,展開是合理的。但可通過以下方式優(yōu)化:
- 使用 category 類型壓縮重復字符串:
for col in ['name', 'city', 'country']:
result[col] = result[col].astype('category')
這可將內(nèi)存占用降低 50% 以上,尤其適用于高基數(shù)分類變量。
- 僅保留必要字段:避免將整個用戶對象展開,只提取分析所需的字段(如
city而非完整address)。
場景 2:以用戶為分析單元(如統(tǒng)計用戶總數(shù)、平均年齡)
此時不應展開訂單。更優(yōu)做法是構建兩個獨立表,模仿星型模型:
用戶表(users):
| user_id | name | age | city | country |
|---|
訂單表(orders):
| user_id | order_id | amount |
|---|
實現(xiàn)方式:
# 用戶表
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)
后續(xù)分析時按需關聯(lián):
# 例如:計算各城市訂單總額
merged = orders.merge(users[['user_id', 'city']], on='user_id')
summary = merged.groupby('city')['amount'].sum()
這種方式避免了冗余,且便于維護和擴展。
場景 3:數(shù)據(jù)規(guī)模極大(百萬級以上)
當數(shù)據(jù)量超出單機內(nèi)存限制時,建議:
- 使用 Polars 或 Dask:它們對嵌套結構支持更好,且支持惰性計算。
- 采用 列式存儲格式(如 Parquet) 并按
user_id分區(qū),減少 I/O 開銷。 - 在 ETL 階段保留原始嵌套結構,在查詢時動態(tài)展開所需部分。
四、不要為了“整齊”而盲目展開
一個常見誤區(qū)是認為“所有數(shù)據(jù)都必須變成寬表才便于分析”。實際上,展開是一種分析前的數(shù)據(jù)準備手段,不是存儲規(guī)范。
在實際項目中,推薦的做法是:
- ETL 階段:保留原始結構或拆分為規(guī)范化表;
- 分析階段:根據(jù)具體問題臨時展開或 join;
- 避免持久化高度冗余的寬表,除非有明確的 BI 報表需求。
此外,手寫循環(huán)解析雖直觀,但難以處理缺失字段、類型不一致等問題,且不可復用。相比之下,json_normalize + explode 的組合更具健壯性和擴展性。
五、總結
處理嵌套 JSON 時,pandas 提供了強大而靈活的工具鏈,但關鍵在于理解數(shù)據(jù)語義與分析目標之間的關系:
- 若分析單位是“子記錄”(如訂單、日志事件),可接受適度冗余,但應優(yōu)化存儲類型;
- 若分析單位是“主實體”(如用戶、設備),應保持數(shù)據(jù)規(guī)范化,通過關聯(lián)獲取細節(jié);
- 對于超大規(guī)模數(shù)據(jù),考慮更現(xiàn)代的分析引擎(如 Polars)或分布式方案。
最終,高效的數(shù)據(jù)處理不在于“能否展開”,而在于“何時展開、展開多少、如何管理冗余”。掌握這一思維,才能在復雜數(shù)據(jù)結構面前游刃有余。
以上就是Pandas合理展開嵌套JSON數(shù)據(jù)的全過程的詳細內(nèi)容,更多關于Pandas展開嵌套JSON數(shù)據(jù)的資料請關注腳本之家其它相關文章!
相關文章
Iconfont(矢量圖標)+iconmoon(圖標svg互轉)配合javascript實現(xiàn)社交分享系統(tǒng)
這篇文章主要介紹了Iconfont(矢量圖標)+iconmoon(圖標svg互轉)配合javascript實現(xiàn)社交分享系統(tǒng),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04
Python實現(xiàn)獲取本機網(wǎng)卡的MAC地址,IP地址和路由表
本文主要為大家詳細介紹了如何在Windows和Mac系統(tǒng)下獲取本機MAC地址和IP地址的方法,以及如何使用ARP協(xié)議獲取局域網(wǎng)內(nèi)所有計算機的IP地址與MAC地址,感興趣的小伙伴可以了解下2026-05-05
Python 安裝 virturalenv 虛擬環(huán)境的教程詳解
這篇文章主要介紹了Python 安裝 virturalenv 虛擬環(huán)境的教程,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2020-02-02

