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

如何在Django中将嵌套JSONField转换为多层索引时序DataFrame

问题描述

我的Django模型包含DateTimeField和JSONField字段,想要基于这些字段创建时序DataFrame。使用django-pandas包的to_timeseries方法可实现基础转换,但该方法会将整个JSONField放入单列中,如何将此列展平为多层索引列?

models.py

class Indicator(models.Model):
    dt = models.DateTimeField(null=True)
    metrics = models.JSONField(default=dict)

JSONField字典示例:

{'housing': {'1d_percent': 73.62755998, '2d_percent': 3e-08},
 'fund-flower': {'ratio': 0.01981295},
 'mpi': {'mpi': -0.6527736158660562}}

现有转换代码及结果:

>>> qs = Indicator.objects.all()
>>> df = qs.to_timeseries(index='dt', fieldnames='metrics').sort_index().dropna()
>>> df

                                                                    metrics
dt                                                                          
2018-01-01 00:00:00+00:00  {'mpi': {'mpi': -0.01679772442974948}, 'fund-f...
2018-01-02 00:00:00+00:00  {'mpi': {'mpi': 1.1785319016689795}, 'fund-flo...
2018-01-03 00:00:00+00:00  {'mpi': {'mpi': 1.047678402830424}, 'fund-flow...
2018-01-04 00:00:00+00:00  {'mpi': {'mpi': 1.111703887319459}, 'fund-flow...
2018-01-05 00:00:00+00:00  {'mpi': {'mpi': 2.3908629334035343}, 'fund-flo...
                                                                      ...
2022-09-17 00:00:00+00:00  {'mpi': {'mpi': -1.0434999082318062}, 'fund-fl...
2022-09-18 00:00:00+00:00  {'mpi': {'mpi': -0.9680468633746766}, 'fund-fl...
2022-09-19 00:00:00+00:00  {'mpi': {'mpi': -0.9287818619840235}, 'fund-fl...
2022-09-20 00:00:00+00:00  {'mpi': {'mpi': -0.8487296227267782}, 'fund-fl...

期望输出:

mpi            fund-flower               housing
dt                          mpi            ratio                     1d_percent    2d_percent                                                                        
2018-01-01 00:00:00+00:00   value          value                     value         value
2018-01-02 00:00:00+00:00   value          value                     value         value  
2018-01-03 00:00:00+00:00   value          value                     value         value  
2018-01-04 00:00:00+00:00   value          value                     value         value  
2018-01-05 00:00:00+00:00   value          value                     value         value  
                                                                      ...
2022-09-17 00:00:00+00:00   value          value                     value         value  
2022-09-18 00:00:00+00:00   value          value                     value         value  
2022-09-19 00:00:00+00:00   value          value                     value         value  
2022-09-20 00:00:00+00:00   value          value                     value         value  

尝试json_normalize时出现错误:

>>> pd.json_normalize(df, record_path =['metrics'])
TypeError: string indices must be integers
解决方案

错误原因分析

报错是因为df['metrics']中的内容可能被django-pandas序列化为字符串,而非Python字典,导致json_normalize无法解析;或是调用参数不符合要求。

方法一:修复django-pandas生成的DataFrame

import pandas as pd
import json

# 1. 原查询集转DataFrame
qs = Indicator.objects.all()
df = qs.to_timeseries(index='dt', fieldnames='metrics').sort_index().dropna()

# 2. 确保metrics列是Python字典(若为字符串则解析)
df['metrics'] = df['metrics'].apply(lambda x: json.loads(x) if isinstance(x, str) else x)

# 3. 逐个规范化JSON字典并合并对齐索引
normalized_df = pd.concat([pd.json_normalize(item) for item in df['metrics']], ignore_index=False)

# 4. 将单层列名转换为多层索引
normalized_df.columns = pd.MultiIndex.from_tuples([tuple(col.split('.')) for col in normalized_df.columns])

print(normalized_df)

方法二:跳过django-pandas,直接构建DataFrame

避免JSON字段被序列化的问题,直接从查询集提取数据:

import pandas as pd
import json

# 1. 从查询集提取数据并构建DataFrame
data = list(Indicator.objects.values('dt', 'metrics'))
df = pd.DataFrame(data).set_index('dt').sort_index().dropna()

# 2. 确保metrics是字典类型
df['metrics'] = df['metrics'].apply(lambda x: json.loads(x) if isinstance(x, str) else x)

# 3. 规范化JSON并转多层索引
normalized_df = pd.concat([pd.json_normalize(item) for item in df['metrics']], ignore_index=False)
normalized_df.columns = pd.MultiIndex.from_tuples([tuple(col.split('.')) for col in normalized_df.columns])

print(normalized_df)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 12:20:40