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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 22:26:00