Gekko调用Pandas DataFrame数据建模时报数据长度匹配错误
问题说明
尝试将理论模型与历史油市数据对比,计划通过Gekko将多个Pandas DataFrame中存储的实测数据输入模型方程,代码运行时抛出数据长度匹配异常,已检查各DataFrame维度一致但无法定位错误原因。
原实现代码
import pandas as pd import pylab as plt import numpy as np from gekko import GEKKO #DATA# #oil supply data = pd.read_html('https://www.eia.gov/dnav/pet/hist/LeafHandler.ashx?n=pet&s=mcrfpus2&f=m') s=data[4] sply = s.loc[s['Year'] >= 1984] supplyvalues = sply.filter(items = ['Jan', 'Feb', 'Mar', 'Apr', 'May','Jun','Jul','Aug','Sep', 'Oct', 'Nov','Dec']) val2 = supplyvalues.dropna() protoval3 = supplyvalues.shift(1) val3=protoval3.dropna() #price of oil p = pd.read_html('https://www.eia.gov/dnav/pet/hist/LeafHandler.ashx?n=PET&s=EMA_EPM0_PTG_NUS_DPG&f=M') Op=p[4] prc = Op.loc[Op['Year'] >= 1984] pricevalues = prc.filter(items = ['Jan', 'Feb', 'Mar', 'Apr', 'May','Jun','Jul','Aug','Sep', 'Oct', 'Nov','Dec']) val1 = pricevalues.dropna() #EQUATION# m=GEKKO() tm = np.linspace(0,10,50) t=m.Param(value = tm) m.time = tm m.options.IMODE=4 #forming equation a,b,c = m.Array(m.Param,3) a.value = val1.values b.value = val2.values c.value = val3.values x = m.Var() m.Equation(a == c-a*b) m.solve(disp=False)
触发的异常
Exception: Data arrays must have the same length, and match time discretization in dynamic problems
错误根因
- 时间离散点长度和输入数据不匹配:代码中硬编码的时间序列
tm仅设置了50个时间点,但1984年至今的月度油市数据共有数百个点,Gekko动态模式要求所有输入参数的长度必须和m.time定义的时间点数量完全一致,这是触发报错的直接原因。 - 数据维度不符合要求:提取的
val1/val2/val3是「年份为行、月份为列」的二维宽表,没有展平为Gekko支持的一维时序数组,即使长度匹配也无法正常赋值。 - 模型逻辑不完整:定义的求解变量
x没有出现在方程中,方程仅包含参数,没有待求解的未知量,即使长度问题修复也无法正常求解。
修复方案
按以下步骤调整代码即可解决问题,新增代码附带作用说明:
- 首先将二维的月度数据表展平为一维时间序列,对齐三个数据集的公共长度,避免缺省值导致的长度差:
# 将按年-月存储的二维宽表展平为按时间排序的一维数组,同时剔除空值 val1_flat = val1.stack().dropna().values val2_flat = val2.stack().dropna().values val3_flat = val3.stack().dropna().values # 取三个序列的最短公共长度,截断所有序列到该长度,保证长度完全一致 data_len = min(len(val1_flat), len(val2_flat), len(val3_flat)) val1_flat = val1_flat[-data_len:] val2_flat = val2_flat[-data_len:] val3_flat = val3_flat[-data_len:]
代码说明:
.stack()会把每行的12个月度值按年份先后顺序拼接,得到连续的月度时间序列;截断操作是为了避免滞后处理、空值剔除导致三个序列长度差1-2个点的问题。
- 调整Gekko时间序列定义,让时间点数量和输入数据长度完全匹配:
m = GEKKO() # 时间序列点数和展平后的数据点数量完全一致,不再硬编码50个点 tm = np.linspace(0, data_len-1, data_len) t = m.Param(value=tm) m.time = tm m.options.IMODE = 4
代码说明:动态仿真模式下
m.time的长度就是模型的时间步总数,所有时序参数、变量的长度必须和这个值一致。
- 修正参数赋值和模型方程,将待求解变量纳入方程:
# 为三个参数赋值对齐后的一维时序数据 a = m.Param(value=val1_flat) b = m.Param(value=val2_flat) c = m.Param(value=val3_flat) # 为求解变量设置初始值,用序列第一个数据点作为初始值 x = m.Var(value=val1_flat[0]) # 替换为实际的理论模型方程,示例为x的动态变化方程,需根据你的理论假设调整 m.Equation(x.dt() == c - a*b) m.solve(disp=False)
代码说明:原方程
a == c-a*b中全是已知参数,不存在待求解的未知量,Gekko无法执行求解;调整后的方程将变量x的变化率和三个输入参数关联,符合动态仿真的逻辑要求,你可以替换为自己推导的理论模型形式。
内容的提问来源于stack exchange,提问作者Ok-Investments
相关产品推荐
相关产品推荐

