SciPy scipy.optimize.minimize约束失效,求收敛解决方案
带约束抛物线拟合的收敛问题解决方法
你的拟合问题中,x的取值范围在258-261之间,x²的量级达到10^5,导致抛物线参数a、b、c的量级差异极大(a对应x²项,c为常数项,量级差数个数量级),这会让优化器的数值计算不稳定,难以收敛。另外,默认的SLSQP算法在处理这类参数量级失衡的约束问题时表现受限。以下是具体的解决方法:
方案1:对x进行平移缩放,平衡参数量级
将x转换为以区间中点为0的新变量,缩小x的数值范围,让参数a、b、c的量级更接近,优化器更容易处理数值计算。
修改后的完整代码:
import scipy import numpy as np import matplotlib.pyplot as plt x = np.array([258.6669469, 258.831, 259.129, 259.428 , 259.726, 260.025, 260.324, 260.622,261.15238824]) y = np.array([0, -0.062, -0.139, -0.181, -0.197, -0.193, -0.17 , -0.129, 0]) # 平移x,让区间中心在0点,缩小数值范围 x_center = (x[0] + x[-1])/2 x_scaled = x - x_center def Func(x,a,b,c): return a*x**2 + b*x + c def FuncCons(x_scaled, params): return params[2]*(x_scaled)**2 + params[1]*(x_scaled) + params[0] def ConstraintIntegral(params): # 积分区间同步使用缩放后的x范围 integral = scipy.integrate.quad(FuncCons, x_scaled[0], x_scaled[-1], args=(params,))[0] return integral - np.trapz(y, x) def ConstraintBegin(params): return y[0] - FuncCons(x_scaled[0], params) def ConstraintEnd(params): return y[-1] - FuncCons(x_scaled[-1], params) def Objective(params, x_scaled, y): y_pred = FuncCons(x_scaled, params) return np.sum((y_pred - y) ** 2) cons = [{'type':'eq', 'fun': ConstraintIntegral}, {'type':'eq', 'fun': ConstraintBegin}, {'type':'eq', 'fun': ConstraintEnd}] # 基于缩放后的x获取初始参数 popt1, _ = scipy.optimize.curve_fit(Func, x_scaled, y) # 使用trust-constr算法优化,适配约束问题 new = scipy.optimize.minimize(Objective, x0=popt1, args=(x_scaled, y), constraints=cons, method='trust-constr') popt3 = new.x # 计算拟合曲线 y_fit1 = Func(x_scaled, *popt1) y_fit3 = FuncCons(x_scaled, popt3) fig, ax = plt.subplots(1) ax.scatter(x, y) ax.plot(x, y_fit1, color='g', alpha=0.75, label='curve_fit') ax.plot(x, y_fit3, color='r', alpha=0.75, label='constrained minimize') plt.legend() plt.show()
方案2:更换优化算法为trust-constr
trust-constr算法专门针对约束优化问题设计,对参数量级的鲁棒性比默认的SLSQP更好,即使不缩放x,也可能直接收敛。只需修改minimize的方法参数:
new = scipy.optimize.minimize(Objective, x0=popt1, args=(x,y), constraints=cons, method='trust-constr')
额外注意事项
- 约束函数的返回值需为等式约束的残差(即目标值为0),你的代码中这部分逻辑正确。
- 保留来自
curve_fit的初始值popt1,它已经是接近最优解的起点,能帮助优化器快速收敛。 - 缩放x后,积分计算的区间必须同步调整,否则会导致积分值错误,破坏约束条件。
内容的提问来源于stack exchange,提问作者andrerud
相关产品推荐
相关产品推荐

