我的目标是根据y=a*x**2 + b *x+c
进行二次曲线拟合,并在两个变量变量a<0
,c<=0
和约束2*a*x+b >=0
上进行边界。简而言之,我希望拟合在y(x = 0)<= 0的第一象限中是单调递增函数。我的示例代码包含使用scipy.optimize.minimize
函数的三个试验:
(1)我没有指定jacobian:在常规数据上工作得很好。
(2)指定jacobian:甚至无法预测常规数据:jacobian定义的一些问题。
(3)应用约束:约束定义引发错误。
我可以引起你的注意,让这个程序运行吗?
import numpy as np
from scipy.optimize import minimize
# scattr-irregular
#xip=np.array([ 0.02237461, 0.0983837 , 0.25707382, 0.56959641, 1.33419197, 4.95835927])
#yip=np.array([0.20085822, 0.23583258, 0.28996988, 0.36350284, 0.47981232, 0.67602165] )
#scatter- regular
xip=np.array([2.12E-01,3.43E-01,5.01E-01,7.01E-01,9.73E-01,1.15E+00,1.34E+00,1.41E+00])
yip=np.array([5.94E-02,1.28E-01,2.05E-01,2.90E-01,3.86E-01,4.34E-01,4.78E-01,4.93E-01])
import matplotlib.pyplot as plt
plt.scatter(xip,yip, label = 'scatter')
xipfit=np.linspace(0, max(xip), 200)
#minimize.scipy
def func(abc,x,y):
""" Objective function """
return ((abc[0]*x**2+abc[1]*x**1+abc[2]-y)**2).sum()
def func_deriv(abc, x,y):
""" Derivative of objective function """
dfda = 2*(abc[0]*x**2+abc[1]*x**1+abc[2]-y)*x**2
dfdb = 2*(abc[0]*x**2+abc[1]*x**1+abc[2]-y)*x**1
dfdc = 2*(abc[0]*x**2+abc[1]*x**1+abc[2]-y)* 1
return np.array([ dfda.sum(), dfdb.sum(), dfdc.sum() ])
#2*a*x+b >=0
cons = ({'type': 'ineq',
'fun' : lambda abc: np.array( [ 2*abc[0]*xip.sum()+abc[1] ]) ,
'jac' : lambda abc: np.array([2*xip.sum(), 1, 0])\
})
######################################################
###1. wO jacobian input; works for specific data.
coeffs_WOjac= minimize(func, x0=[-1.0,1.0,-1], args=(xip,yip),\
jac=False,\
method='SLSQP',\
bounds=((-1e6,0),(0,1e6),(-1e6,0)),\
options={'disp': True})
yipfit_WOjac = coeffs_WOjac.x[0]*xipfit**2\
+coeffs_WOjac.x[1]*xipfit \
+coeffs_WOjac.x[2]
print(coeffs_WOjac)
plt.plot(xipfit,yipfit_WOjac,label='WOjac', linewidth=4)
######################################################
###2. wit jacobian input: fit is not correct. jacobain correct ?
coeffs_Wjac= minimize(func, x0=[-1.0,1.0,-1], args=(xip,yip),\
jac=func_deriv,\
method='SLSQP', \
bounds=((-1e6,0),(-1e6,1e6),(-1e6,0)),\
options={'disp': True})
yipfit_Wjac = coeffs_Wjac.x[0]*xipfit**2\
+coeffs_Wjac.x[1]*xipfit \
+coeffs_Wjac.x[2]
print(coeffs_Wjac)
plt.plot(xipfit,yipfit_Wjac,label='Wjac', color= 'red',linewidth=1.5)
######################################################
###3. wO jacobian and constraints
coeffs_WOjac_constr = minimize(func, x0=[-1.0,1.0,-1], args=(xip,yip),\
jac=False,\
constraints=cons,\
method='SLSQP',
bounds=((-1e6,0),(-1e6,1e6),(-1e6,0)),\
options={'disp': True})
yipfit_WOjac_constr = coeffs_WOjac_constr.x[0]*xipfit**2\
+coeffs_WOjac_constr.x[1]*xipfit \
+coeffs_WOjac_constr.x[2]
plt.plot(xipfit,yipfit_WOjac_constr,label='Wjac_constr', linewidth=2)
plt.legend(loc='upper left')
plt.grid()
我同时尝试在此post中尝试lmfit功能。因此,虽然也引起了对这篇文章的关注。
编辑:代码已重新格式化为取消/评论个别方法。
edit2:正确定义雅可比行列式。
编辑3:工作代码。纳入评论的变化。在cons子程序中删除了xip,yip。