如何将多层字典列表转DataFrame及将DataFrame转时序DataFrame?解决报错
多层数据结构转DataFrame及时序数据转换解决方案
一、报错原因说明
触发TypeError: the JSON object must be str, bytes or bytearray, not Series的核心原因:
- 误将存储Python字典的Series传入了
json.loads()(该函数仅处理JSON字符串) - 使用
pd.json_normalize()时直接传入Series,而非Series中每个元素的字典对象
二、需求1:多层字典列表转DataFrame
直接使用pd.json_normalize()即可自动展开多层嵌套结构,无需额外JSON解析。
代码示例
import pandas as pd # 示例多层字典列表 multi_level_data = [ {"device_id": "dev001", "metadata": {"channel": "CH01", "timezone": "UTC"}, "readings": [12.5, 13.2, 14.1]}, {"device_id": "dev002", "metadata": {"channel": "CH02", "timezone": "GMT+8"}, "readings": [22.3, 23.5, 24.0]} ] # 转换为结构化DataFrame df = pd.json_normalize(multi_level_data) print(df)
输出示例
| device_id | metadata.channel | metadata.timezone | readings |
|---|---|---|---|
| dev001 | CH01 | UTC | [12.5, 13.2, 14.1] |
| dev002 | CH02 | GMT+8 | [22.3, 23.5, 24.0] |
三、需求2:含嵌套字典的DataFrame转时序DataFrame
针对包含Device_id、Attribute_xx列的原DataFrame,需将每个Attribute_xx列的嵌套字典展开,合并为统一的时序结构。
代码实现
import pandas as pd # 模拟原DataFrame结构 original_df = pd.DataFrame({ "Device_id": ["dev001", "dev002"], "Attribute_00": [ {"channel": "CH01", "timezone": "UTC", "Readings": [10, 20, 30]}, {"channel": "CH03", "timezone": "GMT+8", "Readings": [70, 80, 90]} ], "Attribute_01": [ {"channel": "CH02", "timezone": "UTC", "Readings": [40, 50, 60]}, {"channel": "CH04", "timezone": "GMT+8", "Readings": [100, 110, 120]} ] }) # 提取所有Attribute列 attr_columns = [col for col in original_df.columns if col.startswith("Attribute_")] # 批量处理每个Attribute列,生成临时DataFrame后合并 temp_dfs = [] for col in attr_columns: # 关联Device_id与当前列的嵌套字典 temp = original_df[["Device_id", col]].copy() # 展开字典并与Device_id合并 normalized = pd.json_normalize(temp[col]) normalized["device_id"] = temp["Device_id"] # 保留目标列并重命名 normalized = normalized[["device_id", "channel", "timezone", "Readings"]].rename(columns={"Readings": "readings"}) temp_dfs.append(normalized) # 合并所有临时DataFrame timedf = pd.concat(temp_dfs, ignore_index=True) # 可选:将readings列表展开为单条时序记录(根据需求选择) timedf = timedf.explode("readings", ignore_index=True) print(timedf)
输出示例(展开readings后)
| device_id | channel | timezone | readings |
|---|---|---|---|
| dev001 | CH01 | UTC | 10 |
| dev001 | CH01 | UTC | 20 |
| dev001 | CH01 | UTC | 30 |
| dev001 | CH02 | UTC | 40 |
| dev002 | CH03 | GMT+8 | 70 |
| dev002 | CH03 | GMT+8 | 80 |
| dev002 | CH04 | GMT+8 | 100 |
四、优化建议
- 空值处理:处理前先通过
original_df.dropna(subset=attr_columns)过滤含空字典的行,避免报错 - 性能优化:针对超大规模数据,用列表存储临时DataFrame后一次性合并,减少内存开销
- 结构校验:提前用
original_df[attr_columns].applymap(lambda x: isinstance(x, dict))检查列内元素是否为字典,避免类型错误 - 时序扩展:若
readings是含时间戳的嵌套字典(如[{"timestamp": "2024-01-01", "value": 10}, ...]),可再次用pd.json_normalize()展开readings列
内容的提问来源于stack exchange,提问作者Dinesh Nimmagadda
相关产品推荐
相关产品推荐

