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

使用json_normalize处理嵌套列时触发AttributeError问题排查

问题:展开含Decimal类型的嵌套列Pandas DataFrame时触发AttributeError

我有一个Pandas DataFrame,其中2列为包含Decimal类型值的嵌套列,执行df.tail(1).to_dict('list')得到如下数据:

{'nested_col1': [array([{'key1': 'CO', 'key2': Decimal('8.940000000')}], dtype=object)],
 'nested_col2': [array([{'key3': 'CO', 'key4': 'P14', 'key5': Decimal('8.940000000'), 'key6': None}], dtype=object)]}

尝试用以下代码展开DataFrame:

df = (df.drop(cols, axis=1)
        .join(pd.concat(
            [pd.json_normalize(df[x].explode(), errors='ignore').applymap(
                lambda x: str(x) if isinstance(x, (int, float)) else x).add_prefix(f'{x}.') for x in
             cols],
            axis=1)))

但在部分场景下触发报错:

Traceback (most recent call last):
  File "data_load.py.py", line 365, in <module>
    df = prepare_data(data, transaction_id, cohort_no)
  File "data_load.py.py", line 274, in prepare_data
    df = flatten_dataframe(cols_to_explode, df)
  File "data_load.py.py", line 204, in flatten_dataframe
    df1 = pd.concat([pd.json_normalize(df[c].explode()) for c in cols],
  File "data_load.py.py", line 204, in <listcomp>
    df1 = pd.concat([pd.json_normalize(df[c].explode()) for c in cols],
  File "/project1/venv/lib/python3.6/site-packages/pandas/io/json/_normalize.py", line 270, in _json_normalize
    if any([isinstance(x, dict) for x in y.values()] for y in data):
  File "/project1/venv/lib/python3.6/site-packages/pandas/io/json/_normalize.py", line 270, in <genexpr>
    if any([isinstance(x, dict) for x in y.values()] for y in data):
AttributeError: 'float' object has no attribute 'values'
failed to run commands: exit status 1

期望输出为带前缀的列名,格式如下:

nested_col1.key1,nested_col1.key2,nested_col2.key3...

请问我是否遗漏了什么?有没有更优的实现方式?


解决方案

错误原因

报错是因为df[c].explode()后出现了float类型的值(大概率是np.nan),而非预期的字典/嵌套结构。旧版本的pd.json_normalize会尝试遍历元素的.values()方法,但float类型没有这个属性,因此触发AttributeError。

优化实现代码

from decimal import Decimal
import numpy as np
import pandas as pd

def flatten_nested_columns(df, target_cols):
    flattened_dfs = []
    for col in target_cols:
        # 1. 预处理:把非数组/字典的元素转为包含空字典的数组,避免explode后出现单个非字典值
        processed = df[col].apply(
            lambda x: x if isinstance(x, (list, np.ndarray)) else [{}] if pd.isna(x) else [x]
        )
        # 2. 展开嵌套数组
        exploded = processed.explode()
        # 3. 标准化字典:转换Decimal为字符串,确保每个元素都是字典
        normalized_df = pd.json_normalize(
            exploded.apply(
                lambda x: {k: str(v) if isinstance(v, Decimal) else v for k, v in x.items()} 
                if isinstance(x, dict) else {}
            )
        ).add_prefix(f"{col}.")
        flattened_dfs.append(normalized_df)
    
    # 合并原表(移除原嵌套列)和展开后的列
    return df.drop(target_cols, axis=1).join(pd.concat(flattened_dfs, axis=1))

# 调用示例
cols = ["nested_col1", "nested_col2"]
df = flatten_nested_columns(df, cols)

关键处理点

  • 异常值预处理:提前把NaN或单个非字典值转为包含空字典的数组,确保explode后所有元素都是可解析的结构
  • Decimal类型转换:显式将Decimal转为字符串,避免后续序列化或类型兼容问题
  • 容错性保障:强制确保传给pd.json_normalize的每个元素都是字典,即使是空字典,避免旧版Pandas的解析报错

额外注意

你的环境使用的是Python3.6搭配旧版Pandas,pd.json_normalize的容错性较差,提前做数据清洗是关键。如果存在多层嵌套需求,可以给pd.json_normalize添加max_level参数控制展开深度。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 03:05:38