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

Python中如何展开多列类JSON格式单元格,pd.json_normalize无效怎么办

多列混合JSON格式单元格展开最优方案

不同列的JSON结构不一致(有单字典、列表嵌套字典、空值三种情况),直接调用pd.json_normalize()无法适配多种结构,按列分批次处理是通用性最高的方案:

第一步:修正测试数据构造代码

原给出的df构造代码包含多余引号,修正后可直接运行:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'authors': pd.Series([
        [{'name': '/u/Ashamed_Boss2510', 'href': 'https://www.reddit.com/user/Ashamed_Boss2510'}], 
        [{'name': '/u/lazywizard99', 'href': 'https://www.reddit.com/user/lazywizard99'}], 
        [{'name': '/u/Guy_PCS', 'href': 'https://www.reddit.com/user/Guy_PCS'}]
    ], dtype='object', index=pd.RangeIndex(start=1, stop=4, step=1)), 
    'author_detail': pd.Series([
        {'name': '/u/Ashamed_Boss2510', 'href': 'https://www.reddit.com/user/Ashamed_Boss2510'}, 
        {'name': '/u/lazywizard99', 'href': 'https://www.reddit.com/user/lazywizard99'}, 
        {'name': '/u/Guy_PCS', 'href': 'https://www.reddit.com/user/Guy_PCS'}
    ], dtype='object', index=pd.RangeIndex(start=1, stop=4, step=1)), 
    'title_detail': pd.Series([
        {'type': 'text/plain', 'language': None, 'base': 'https://www.reddit.com/r/StockMarket/.rss', 'value': 'Always have an exit strategy!'}, 
        {'type': 'text/plain', 'language': None, 'base': 'https://www.reddit.com/r/StockMarket/.rss', 'value': 'Nikola reports yet another loss with $0 revenue'}, 
        {'type': 'text/plain', 'language': None, 'base': 'https://www.reddit.com/r/StockMarket/.rss', 'value': 'This crypto scam bilked investors out of $11 million — and paid action star Steven Seagal to promote it. What was left unsaid was that Seagal was being paid to be a spokesman, with the promise of $250,000 plus $750,000 in B2G coin for his time, the SEC said.'}
    ], dtype='object', index=pd.RangeIndex(start=1, stop=4, step=1)), 
    'media_thumbnail': pd.Series([
        np.nan, 
        [{'url': 'https://external-preview.redd.it/fcUXTQfhTGh8Pgf3r-NT8tejZU7c-e73eylUXQmsjGk.jpg?width=640&crop=smart&auto=webp&s=b23eeb929e75fb34da96509017784b9e29a0974f'}], 
        [{'url': 'https://external-preview.redd.it/L-WoVKyLp1qifGqMEXat-zP64V9qW-pfE_4brQwU_fg.jpg?width=640&crop=smart&auto=webp&s=bea54909841c2ca86571494226c47deb9c2a9d2e'}]
    ], dtype='object', index=pd.RangeIndex(start=1, stop=4, step=1))
}, index=pd.RangeIndex(start=1, stop=4, step=1))

第二步:按列类型分别展开

# 处理单字典结构列:author_detail、title_detail,直接展开后加前缀避免重名
author_detail_df = pd.json_normalize(df['author_detail']).add_prefix('author_detail_')
title_detail_df = pd.json_normalize(df['title_detail']).add_prefix('title_detail_')

# 处理列表嵌套字典列:authors
# 先炸开列表为单个字典,再展开,保留原索引对齐
authors_df = df['authors'].explode().pipe(pd.json_normalize).add_prefix('authors_').set_index(df.index)

# 处理带空值的列表嵌套字典列:media_thumbnail
# 先处理空值,把非空列表取出第一个字典(如果列表包含多个元素,保留explode逻辑即可)
media_df = df['media_thumbnail'].apply(
    lambda x: x[0] if isinstance(x, list) and len(x) > 0 else {}
).pipe(pd.json_normalize).add_prefix('media_thumbnail_').set_index(df.index)

# 合并所有展开后的列,不需要原JSON列的话可以提前删除
result_df = pd.concat([
    df.drop(columns=['authors', 'author_detail', 'title_detail', 'media_thumbnail']),
    author_detail_df,
    title_detail_df,
    authors_df,
    media_df
], axis=1)

方案适配性说明

  • 如果某列的列表包含多个元素(比如一个条目对应多个作者),只要删掉取第一个元素的逻辑,保留explode后和原表按索引合并即可生成多行行数据,适配一对多场景
  • 所有空值、空列表场景会自动填充NaN,不会触发解析报错
  • 列前缀可按需修改,避免不同列的同名字段冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 18:15:02