主要内容

基于问题的非线性数据拟合方法

对于最小二乘问题设置的一般建议是以允许的方式来表述问题解决认识到问题具有最小二乘形式。当你这样做的时候,解决在内部调用lsqnonlin,它在求解最小二乘问题时很有效。看到为基于问题的最小二乘编写目标函数

这个例子通过比较最小二乘求解器的性能来说明最小二乘求解器的效率lsqnonlin与…fminunc同样的问题。此外,该示例还显示了通过显式地识别和单独处理问题的线性部分可以获得的额外好处。

问题的设置

考虑以下数据:

Data =[0.0000 5.8955 0.1000 3.5639 0.2000 2.5173 0.3000 1.9790 0.4000 1.8990 0.5000 1.3938 0.6000 1.1359 0.7000 1.0096 0.8000 1.0343 0.9000 0.8435 1.0000 0.6856 1.1000 0.6100 1.2000 0.5392 1.3000 0.3946 1.4000 0.3903 1.5000 0.5474 1.6000 0.3459 1.7000 0.1370 1.8000 0.2211 1.9000 0.1704 2.0000 0.2636];

绘制数据点。

t = Data(:,1);y = Data(:,2);情节(t y“罗”)标题(的数据点

图包含一个轴对象。标题为Data points的axes对象包含一个仅使用标记显示其值的line对象。

问题是如何拟合函数

Y = c(1)*exp(-lam(1)*t) + c(2)*exp(-lam(2)*t)

对数据。

使用默认求解器的解决方法

首先,定义与方程对应的优化变量。

C = optimvar()“c”2);Lam = optimvar(“林”2);

任意设置初始点x0如下:C (1) = 1C (2) = 1Lam (1) = 1,Lam (2) = 0

0.c = [1,1];x0。Lam = [1,0];

创建一个函数来计算响应的值t当参数为c

diffun = c (1) * exp (lam (1) * t) + c (2) * exp (lam (2) * t);

转换diffun到一个优化表达式,该表达式对函数和数据之间的差的平方求和y

Diffexpr = sum((diffun - y).^2);

创建一个优化问题diffexpr作为目标函数。

Ssqprob = optimproblem()“目标”, diffexpr);

使用默认解算器解决问题。

[sol,fval,exitflag,output] = solve(ssqprob,x0)
使用lsqnonlin解决问题。局部最小值。Lsqnonlin停止是因为相对于其初始值的平方和的最终变化小于函数容差的值。
索尔=带有字段的结构体:C: [2x1双]lam: [2x1双]
Fval = 0.1477
exitflag = FunctionChangeBelowTolerance
输出=带有字段的结构体:firstorderopt: 7.8870e-06迭代:6 funcCount: 7 cgiterations: 0算法:'trust-region-reflective'步长:0.0096消息:'本地最小可能....* * * * * * * * * * * * * * * * * * * * * * * * *

根据返回的解值绘制结果曲线sol.csol.lam

Resp = evaluate(diffun,sol);持有情节(t,职责)

图包含一个轴对象。标题为Data points的axes对象包含2个line类型的对象。其中一行或多行仅使用标记显示其值

看起来合身得再好不过了。

解决方法fminunc

解决问题使用fminunc求解器,设置“规划求解”选项“fminunc”当调用解决

[xunc,fvalunc,exitflagunc,output] = solve(ssqprob,x0,)“规划求解”“fminunc”
使用fminunc解决问题。找到局部最小值。优化完成是因为梯度的大小小于最优容差的值。
xunc =带有字段的结构体:C: [2x1双]lam: [2x1双]
Fvalunc = 0.1477
exitflagunc = OptimalSolution
outputunc =带有字段的结构体:迭代:30 funcCount: 37 stepsize: 0.0017 lssteplength: 1 firstorderopt: 2.9454e-05算法:'准牛顿'消息:'找到本地最小值....目标导数:“forward-AD”解算器:“fminunc”

请注意,fminunc找到了相同的解lsqcurvefit,但需要进行更多的函数求值。的参数fminunc和那些的顺序相反吗lsqcurvefit;更大的林(2),而不是林(1)。这并不奇怪,变量的顺序是任意的。

流([使用fminunc进行了%d次迭代。'和%d使用lsqcurvefit.\n'],outputunc.iterations output.iterations)
使用fminunc进行了30次迭代,使用lsqcurvefit进行了6次迭代。
流([“使用fminunc计算了%d个函数。”'和%d使用lsqcurvefit。'],outputunc.funcCount output.funcCount)
使用fminunc进行了37次函数评估,使用lsqcurvefit进行了7次。

分解线性和非线性问题

注意拟合问题在参数上是线性的c (1)c (2)。这意味着对于的任何值林(1)林(2),您可以使用反斜杠操作符查找的值c (1)c (2)这就解决了最小二乘问题。

将问题作为二维问题,寻找的最佳值林(1)林(2)。的值c (1)c (2)使用如上所述的反斜杠操作符在每一步计算。要做到这一点,使用fitvector函数,该函数执行反斜杠操作以获取c (1)c (2)在每次求解器迭代中。

类型fitvector
function yEst = fitvector(lam,xdata,ydata) % fitvector DATDEMO用于返回拟合函数的值。% est = FITVECTOR(lam,xdata)返回数据点xdata处拟合函数y %(定义如下)的值,参数设置为lam。% est作为N × 1列向量返回,其中N是%数据点的个数。% % FITVECTOR假设拟合函数y的形式为% % y = c(1)*exp(-lam(1)*t) +…+ c(n)*exp(-lam(n)*t) % %, n个线性参数c, n个非线性参数lam。为了求解线性参数c,我们建立一个矩阵a,其中a的第j列是exp(-lam(j)*xdata) (xdata是一个向量)。然后我们求解线性最小二乘解c的A*c = ydata,其中ydata是y的观测值。%构建一个j = 1的矩阵:length(lam) A(:,j) = exp(-lam(j)*xdata);end c = A\ydata;%求解A*c = y的线性参数c yEst = A*c; % return the estimated response based on c

使用解决问题解决从二维初始点开始x02.lam(1,0)。为此,首先转换fitvector函数转换为一个优化表达式fcn2optimexpr。看到将非线性函数转换为优化表达式。为避免出现警告,请给出结果表达式的输出大小。创建一个新的优化问题,目标为两者之间的转换平方和fitvector功能与数据y

x02.lam=x0。林;F2 = fcn2optimexpr(@(x) fitvector(x,t,y),lam,“OutputSize”,长度(t) 1);Ssqprob2 = optimproblem(“目标”,sum((F2 - y) ^2));[sol2,fval2,exitflag2,output2] = solve(ssqprob2,x02)
使用lsqnonlin解决问题。局部最小值。Lsqnonlin停止是因为相对于其初始值的平方和的最终变化小于函数容差的值。
sol2 =带有字段的结构体:Lam: [2x1 double]
Fval2 = 0.1477
exitflag2 = FunctionChangeBelowTolerance
output2 =带有字段的结构体:firstorderopt: 4.4032e-06迭代:10 funcCount: 33 cgiterations: 0算法:'trust-region-reflective'步长:0.0080消息:'本地最小可能....[]目标导数:“有限差分”约束导数:“自动”求解器:“lsqnonlin”

二维解的效率与四维解的效率相似:

流([“有%d函数评估使用了2d”'配方,%d使用4-d配方。'],output2.funcCount output.funcCount)
使用二维公式有33个函数评价,使用4d公式有7个函数评价。

拆分问题对初始猜测的鲁棒性更好

为最初的四参数问题选择一个不好的起点会导致局部解决方案而不是全局解决方案。选择一个同样糟糕的起点林(1)林(2)拆分的双参数问题的值导致全局解。为了说明这一点,可以重新运行导致相对较差的局部解决方案的原始问题,并将结果与全局解决方案进行比较。

xx .c = [51];x0bad。林=[1 0]; [solbad,fvalbad,exitflagbad,outputbad] = solve(ssqprob,x0bad)
使用lsqnonlin解决问题。局部最小值。Lsqnonlin停止是因为相对于其初始值的平方和的最终变化小于函数容差的值。
solbad =带有字段的结构体:C: [2x1双]lam: [2x1双]
Fvalbad = 2.2173
exitflagbad = FunctionChangeBelowTolerance
outputbad =带有字段的结构体:firstorderopt: 0.0036迭代:31 funcCount: 32 cgiterations: 0算法:'trust-region-reflective'步长:0.0012消息:'本地最小可能....* * * * * * * * * * * * * * * * * * * * * * * * *
Respbad = evaluate(diffun,solbad);持有情节(t, respbad‘g’)传说(“数据”“全球健康”“不适应当地环境”“位置”“不”)举行

图包含一个轴对象。标题为Data points的axis对象包含3个类型为line的对象。其中一行或多行仅使用标记显示其值。这些对象表示Data、Global fit、Bad local fit。

流([“良好终点的残差规范是%f,”在糟糕的终点处的残差范数是%f。],fval fvalbad)
好的终点残差范数为0.147723,坏的终点残差范数为2.217300。

另请参阅

|

相关的话题