Gekko回归IMODE下多方程最小化:不同规模数据集适配问题排查
多数据集共享变量的Gekko回归问题解决方案
问题背景
需要用Gekko求解共享变量v1、v2的双方程优化问题,目标是最小化两个不同规模数据集的预测值与实测值的相对误差平方和。运行代码时遇到两类错误:
- 数据集行数不同时:
Data arrays must have the same length, and match time discretization in dynamic problems - 强行统一行数后:
duplicate variable declarations
问题定义
- 共享变量:
v1, v2 - 数据集参数:
- 数据集1:
ds1_p1, ds1_p2(50行) - 数据集2:
ds2_p1, ds2_p2, ds2_p3(100行)
- 数据集1:
- 预测方程:
y1 = v1 * ds1_p1 + v2 * ds1_p2 y2 = v1 * v2 * ds2_p1 + v1 * ds2_p2 + v2 * ds2_p3 - 目标函数:最小化两项相对误差平方的总和
((y1_pred - y1_meas)/y1_meas)^2 ((y2_pred - y2_meas)/y2_meas)^2
错误原因
- 数据集维度不匹配:Gekko的IMODE=2(回归模式)默认要求所有参数、变量的维度一致,不同长度的数据集会打破这种离散点对齐规则。
- 重复变量声明:原代码中不同数据集的参数使用了相同的
name(如p1),导致Gekko识别为重复变量。
修正后的代码
import numpy as np from gekko import GEKKO # 初始化Gekko模型 m = GEKKO() # 定义共享可调变量(FV用于回归优化) v_dic = { "v1": m.FV(value=1, lb=0, ub=2, name="v1"), "v2": m.FV(value=3, lb=1, ub=5, name="v2") } # 允许优化器调整变量 for var in v_dic.values(): var.STATUS = 1 # 生成模拟数据集(不同长度) np.random.seed(42) # 固定随机种子保证结果可复现 parameters = { "dataset1": {f"p{i}": np.random.random(50) for i in range(1, 3)}, "dataset2": {f"p{i}": np.random.random(100) for i in range(1, 4)}, } # 创建参数:添加数据集前缀避免重名 p_dic = {} for ds_name, ds_params in parameters.items(): p_dic[ds_name] = {} for par_name, par_val in ds_params.items(): p_dic[ds_name][par_name] = m.Param(value=par_val, name=f"{ds_name}_{par_name}") # 生成模拟实测值(假设真实v1=2,v2=4) ym = {} ym["dataset1"] = { "ymeas": 2 * parameters["dataset1"]["p1"] + 4 * parameters["dataset1"]["p2"] } ym["dataset2"] = { "ymeas": 2*4*parameters["dataset2"]["p1"] + 2*parameters["dataset2"]["p2"] + 4*parameters["dataset2"]["p3"] } # 创建实测值参数:添加唯一命名 ym_dic = {} for ds_name, ds_val in ym.items(): ym_dic[ds_name] = m.Param(value=ds_val["ymeas"], name=f"{ds_name}_ymeas") # 创建与数据集长度匹配的预测值数组变量 yp_dic = {} for ds_name in ym_dic.keys(): yp_dic[ds_name] = m.Var(value=np.zeros(len(ym_dic[ds_name].value)), name=f"{ds_name}_ypred") # 逐元素定义预测方程 # 数据集1的方程 for i in range(len(parameters["dataset1"]["p1"])): m.Equation(yp_dic["dataset1"][i] == v_dic["v1"] * p_dic["dataset1"]["p1"][i] + v_dic["v2"] * p_dic["dataset1"]["p2"][i]) # 数据集2的方程 for i in range(len(parameters["dataset2"]["p1"])): m.Equation(yp_dic["dataset2"][i] == v_dic["v1"]*v_dic["v2"]*p_dic["dataset2"]["p1"][i] + v_dic["v1"]*p_dic["dataset2"]["p2"][i] + v_dic["v2"]*p_dic["dataset2"]["p3"][i]) # 累加所有数据点的相对误差平方作为目标 for ds_name in yp_dic.keys(): for i in range(len(ym_dic[ds_name].value)): m.Minimize( ((yp_dic[ds_name][i] - ym_dic[ds_name][i]) / ym_dic[ds_name][i])**2 ) # 设置回归模式与求解器 m.options.IMODE = 2 m.options.SOLVER = 3 # 使用IPOPT求解器 m.solve(disp=False) # 关闭屏幕输出,调试时可设为True # 输出求解结果 print("求解结果:") for name, var in v_dic.items(): print(f"{name} = {var.value[0]:.4f}")
关键修正说明
- 唯一命名规则:为所有参数、变量添加数据集前缀,避免重复声明冲突。
- 数组变量适配:创建与数据集长度匹配的数组变量存储预测值,逐个数据点定义方程,解决不同长度数据集的对齐问题。
- 逐点误差累加:遍历每个数据点计算相对误差平方并加入目标函数,确保所有样本的误差都被纳入优化目标。
内容的提问来源于stack exchange,提问作者Florent H
相关产品推荐
相关产品推荐

