python - 如何在 Python Curve_fit 上设置两个参数之间的不等式?
问题描述
所以,我正在编写一个程序来将 5 参数函数 (s,t,k,h,b) 拟合到一组实验数据。好吧,该程序有效,但我需要满足一个条件:0<k<h<1。我只需要将这个不等式添加到拟合过程中。任何人都可以帮忙吗?
算法是:
import xlrd
import numpy
import math
import scipy
from scipy.optimize import curve_fit
workbook = xlrd.open_workbook('Pasta3.xls')
sheet = workbook.sheet_by_name('teste')
x = []
for i in range (18):
cell = sheet.cell_value(i+1,1)
x.append(cell)
y = []
for i in range (18):
cell_=sheet.cell_value(i+1,0)
y.append(cell_)
def Re(x,s,t,k,h,b):
return 130 + ((38000-130)*(1+s*((2*math.pi*x*t)**(-1*k))*math.cos(k*math.pi/2)+ ((2*math.pi*x*t)**(-1*h))*math.cos(h*math.pi/2)))/((((38000-130)*(1+s*((2*math.pi*x*t)**(-1*k))*math.cos(k*math.pi/2)+((2*math.pi*x*t)**(-1*h))*math.cos(h*math.pi/2)))/(38000-130))**2+(((38000-130)*(s*((2*math.pi*x*t)**(-1*k))*math.sin(k*math.pi/2)+((2*math.pi*x*t)**(-1*h))*math.sin(h*math.pi/2)+((2*math.pi*x*t*b)**(-1))))/(38000-130))**2)
popt, _ = curve_fit(Re,x,y)
print(popt)
解决方案
添加不等式约束的一种方法是使用该lmfit
库。它的特点之一是能够以数学表达式的形式施加约束。结合简单的上限和下限,允许不等式约束。
对于您的示例,转换为使用 lmfit (可能会进行一些清理以确保所有内容都是 numpy ndarray)将给出如下结果:
import xlrd
from numpy import array, pi, sin, cos
from lmfit import Model
workbook = xlrd.open_workbook('Pasta3.xls')
sheet = workbook.sheet_by_name('teste')
x = []
for i in range (18):
cell = sheet.cell_value(i+1,1)
x.append(cell)
y = []
for i in range (18):
cell_=sheet.cell_value(i+1,0)
y.append(cell_)
x = array(x)
y = array(y)
def Re(x, s, t, k, h, b):
xt = 2*pi*xt
sxtk = s*xt**(-k)
xth = xt**(-h)
scale= 38000-130
term1 = 1 + sxtk*cos(k*pi/2) + xth*cos(h*pi/2)
term2 = sxtk*sin(k*pi/2) + xth*sin(h*pi/2)+(1/(xt*b))
return 130 + scale**2 * term1/ (term1 + term2)
model = lmfit.Model(Re)
params = model.make_params(s=0.5, t=0.5, k=0.2, h=0.5, b=0.5)
result = model.fit(y, params, x=x)
print(result.fit_report())
一些重要的注意事项:
可读性很重要。真的,它比什么都重要,这就是你选择 Python 的原因。没有人 - 包括你 - 会理解你的拟合功能的混乱。这使得它完全没用:即使它很合身,你也不会知道它做了什么。我做了一些重构和简化,但你当然想检查一下。
您的示例没有给出拟合参数的初始值。
scipy.optimize.curve_fit()
静默允许这一点,将所有参数的值设为 1。这是一个可怕的错误功能,会给许多用户带来麻烦。是的,这似乎是额外的工作,但拟合方法需要初始值。您始终需要提供对您的数据有意义的初始值。没有例外。
在示例lmfit
中,每个参数都具有初始值。在这里,它们都设置为 0 到 1 之间的值,但您需要将它们设置为数据的合理初始值。
要设置参数的界限,您可以这样做
params['k'].min = 0
params['k'].max = 1
等等。要这么说h > k
,您将定义一个新参数——我将其命名为h_minus_k
,然后使用数学表达式设置h
为从该值计算得出k
:
params.add('h_minus_k', value=0.1, min=0, max=1)
params['h'].expr = 'k + h_minus_k'
现在,既然h_minus_k
不能为负数,h>k
就会保持。拟合中仍有 5 个变量,now s
、t
、k
、b
和h_minus_k
。 h
将在拟合中变化,但不是自由变化 - 它的值受k
和的值约束h_minus_k
。有了这个约束,您可以再次尝试拟合并比较结果:
params = model.make_params(s=0.5, t=0.5, k=0.2, h=0.5, b=0.5)
params['k'].min = 0
params['k'].max = 1
params['h'].min = 0
params['h'].max = 1
params.add('h_minus_k', value=0.1, min=0, max=1)
params['h'].expr = 'k + h_minus_k'
result2 = model.fit(y, params, x=x)
print(result2.fit_report())
推荐阅读
- c# - 使用 String.Split 时跨 2 个数据集的 Linq 查询
- pine-script - 绘制自 pine 编辑器中列出的 MACD 的 ATH
- android - Camera1 API + 在使用 MediaRecorder 处理之前编辑视频帧
- python - 有没有办法为 SWIG 的默认标准字符串参数生成函数注释?
- video - 如何将“scale2ref”集成到这个 ffmpeg 代码中?
- android - 如何使用 OneSignal 从 android 应用程序发送字符串?
- reactjs - 为什么我获取的数据没有出现在我的 React hooks 组件中?
- javascript - 入口点和基于路由的拆分有什么区别
- git - 在 vagrant 中更新 git 凭据
- javascript - 页面加载时运行的 JavaScript