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

如何将含嵌套数组的啤酒配方JSON转为扁平化Pandas DataFrame

啤酒配方JSON嵌套数组扁平化及KeyError问题解决

问题背景

拥有包含嵌套数组(如fermentables、hops等字段)的啤酒配方JSON数据,使用pandas.json_normalize无法完全扁平化;修改代码后出现KeyError: 0错误,需要适配不同配方嵌套数组长度不固定的场景,实现完整扁平化的DataFrame转换。

错误原因分析

  1. 索引不匹配:代码中执行df = df.T转置DataFrame后,原JSON的键成为了新的索引,而非数字序列,因此使用df.at[0, 'hops']查找索引为0的行时,会因索引不存在触发KeyError。
  2. 错误的嵌套处理逻辑:直接将嵌套数组转为DataFrame并存入原表列中,并未实现真正的扁平化,反而导致表结构混乱,后续操作容易出错。

解决方案

方案1:针对嵌套数组分别展开(推荐,适配任意长度嵌套)

该方案将每个嵌套数组单独展开为带配方标识的DataFrame,适合需要单独分析发酵原料、酒花等子数据的场景,也可根据配方ID合并数据。

import json
import pandas as pd

# 加载JSON数据
filename = 'recipes_full copy.json'
with open(filename, 'r') as f:
    try:
        json_data = json.load(f)
        print("JSON文件有效")
    except ValueError as e:
        print("JSON文件无效:", e)

# 统一数据格式:如果原始JSON是字典(键为配方ID),转为带配方ID的列表
if isinstance(json_data, dict):
    recipes_list = [{"recipe_id": recipe_key, **recipe_info} for recipe_key, recipe_info in json_data.items()]
else:
    recipes_list = json_data

# 展开fermentables(发酵原料)字段,保留配方顶层信息
df_fermentables = pd.json_normalize(
    recipes_list,
    record_path='fermentables',  # 指定要展开的嵌套数组字段
    meta=['recipe_id', 'name', 'style']  # 保留配方的顶层字段,按需添加
)

# 展开hops(酒花)字段,保留配方顶层信息
df_hops = pd.json_normalize(
    recipes_list,
    record_path='hops',
    meta=['recipe_id', 'name', 'style']
)

# 可选:根据recipe_id合并两个表(注意:若一个配方有多个发酵原料和酒花,会产生笛卡尔积,按需选择)
# df_combined = pd.merge(df_fermentables, df_hops, on='recipe_id', suffixes=('_ferm', '_hop'))

方案2:将嵌套数组扁平化到同一行(生成多列)

如果需要把每个配方的所有嵌套信息放在同一行,会生成类似fermentables_0_name、fermentables_1_name的列,适合嵌套数组长度较短的场景。

import json
import pandas as pd

# 加载并格式化数据(同方案1)
filename = 'recipes_full copy.json'
with open(filename, 'r') as f:
    try:
        json_data = json.load(f)
        print("JSON文件有效")
    except ValueError as e:
        print("JSON文件无效:", e)

if isinstance(json_data, dict):
    recipes_list = [{"recipe_id": k, **v} for k, v in json_data.items()]
else:
    recipes_list = json_data

# 定义扁平化嵌套字段的函数
def flatten_nested_column(df, nested_col_name):
    # 将嵌套数组展开为多列,添加前缀区分
    nested_df = df[nested_col_name].apply(pd.Series).add_prefix(f"{nested_col_name}_")
    # 合并回原表并删除原嵌套列
    return pd.concat([df.drop(nested_col_name, axis=1), nested_df], axis=1)

# 初始化顶层配方DataFrame
df_recipes = pd.DataFrame(recipes_list)

# 依次扁平化fermentables和hops
df_recipes = flatten_nested_column(df_recipes, 'fermentables')
df_recipes = flatten_nested_column(df_recipes, 'hops')

# 查看结果
print(df_recipes.head())

关键说明

  • 若原始JSON是字典结构(键为配方唯一标识),必须先转为带recipe_id的列表,否则json_normalize无法正确识别嵌套关系。
  • 方案1的展开方式更灵活,能适配任意长度的嵌套数组,且不会因嵌套项数量不同导致数据缺失;方案2适合需要紧凑展示单配方全量信息的场景,但嵌套项过多时会生成大量列。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:13:37