非线性数据近似
导言
在这个例子中,我们将研究如何使用各种Julia算法从数据中近似非线性函数。
添加必要的库:
using Plots, LsqFit, Optim
设置任务
任务是使用以下数据近似函数:
xdata = [
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 = xdata[:, 1];
y = xdata[:, 2];
图1=图();
scatter!(t, y, title = "数据点", markerstrokecolor = :blue, markercolor = :white, markerstrokewidth = 1, markersize = 4, legend = false);
显示(图1)
让我们尝试近似函数 到图上的数据。
使用curve_fit函数的解
为了使用curve_fit将函数近似为数据,我们将函数中的参数与变量x进行比较,如下所示:
x(1)=
x(2)=
x(3)=
x(4)=
让我们定义一个近似函数:
F(xdata, x) = x[1] * exp.(-x[2] .* xdata) + x[3] * exp.(-x[4] .* xdata);
我们任意设定起点x0如下:
x0 = [1.0, 1.0, 1.0, 0.0];
让我们运行curve_fit函数并绘制结果近似值。:
start_time = time()
fit = curve_fit(F, t, y, x0);
x = fit.param;
resnorm = sum(fit.resid.^2);
elapsed_time = time() - start_time;
println(x)
println("计算时间:$elapsed_time秒")
график2 = scatter(t, y, markerstrokecolor=:blue, markercolor=:white, markerstrokewidth=1, markersize=4, label="数据点")
plot!(t, F(t, x), linewidth=2, color=:blue, label="近似值")
title!("近似值")
显示(图2)
使用优化功能的解决方案
为了使用optimize解决问题,我们将目标函数定义为残差的平方和。:
Fsumsquares(x) = sum((F(t, x) - y).^2);
start_time = time()
result = optimize(Fsumsquares, x0, LBFGS());
xunc = Optim.minimizer(result) ;
ressquared = Optim.minimum(result) ;
eflag = Optim.converged(result) ? 1 : 0 ;
elapsed_time = time() - start_time;
println(xunc)
println("计算时间:$elapsed_time秒")
请注意,optimize找到与curve_fit相同的解决方案,但需要更多时间进行计算。 由于变量的顺序是任意的,计算结果以不同的顺序排列。
线性和非线性任务的分离
请注意,近似问题在参数方面是线性的 和 . 这意味着对于任何值 和 您可以使用逆除法运算符来查找解决最小二乘问题的C₁和c₂的值。
我们通过搜索最优值将问题重新定义为二维。 和 . 价值 和 在每个步骤中使用逆除法运算符计算。
function fitvector(lam, xdata, ydata)
A = [exp(-λ * x) for x in xdata, λ in lam]
c = A \ ydata
yEst = A * c
return yEst
end
让我们使用curve_fit解决问题,从二维起点[1,0]开始:
x02 = [1.0, 0.0];
F2(t_data, x) = fitvector(x, t_data, y)
start_time = time()
fit2 = curve_fit(F2, t, y, x02);
x2 = fit2.param;
resnorm2 = sum(fit2.resid.^2);
exitflag2 = fit2.converged ? 1 : 0;
elapsed_time = time() - start_time;
println(x2)
# println("计算时间:$elapsed_time秒")
分裂问题对初始近似最稳定
为具有四个参数的初始问题选择不成功的起始点会导致不是全局的局部解决方案。 然而,为具有两个参数的分裂问题选择具有相同λί和λί的不成功值的起点导致全局解。 为了证明这个结果,让我们用一个导致相对不成功的局部解的起点重新开始原始问题,并将得到的近似值与全局解进行比较。
x0bad = [10.0, 1.0, 1.0, 0.0]
start_time = time()
fitbad = curve_fit(F, t, y, x0bad);
xbad = fitbad.param;
resnormbad = sum(fitbad.resid.^2);
exitflagbad = fitbad.converged ? 1 : 0;
elapsed_time = time() - start_time;
println(xbad)
println("计算时间:$elapsed_time秒")
график3 = scatter(t, y, markerstrokecolor=:blue, markercolor=:white, markerstrokewidth=1, markersize=4, label="数据资料")
plot!(t, F(t, x), linewidth=2, color=:blue, label="成功参数")
plot!(t, F(t, xbad), linewidth=2, color=:red, label="失败的参数")
title!("近似值")
显示(图3)
println("成功终点的残差率:$(resnorm);")
println("失败端点处的剩余范数为$(resnormbad)。")
结论
此示例演示了使用优化技术的非线性数据近似的关键方面。:
专用算法的效率-专为曲线近似任务设计的curve_fit函数与optimize*函数相比显示出显着更高的效率,需要更少的目标函数计算才能获得相同的结果。
*参数分离的重要性-问题的线性参数的分配使得可以将初始四参数问题显着简化为二维问题,这不仅保留了计算效率,而且增加了方法的稳定性。
*初始近似值的稳定性-问题的分割公式显示了更高的可靠性,允许避免局部最小值并找到全局解决方案,即使初始参数值选择不成功。
*实际意义-所提出的方法在需要通过复杂非线性模型精确逼近实验数据的各个领域具有广泛的适用性,包括化学动力学,生物过程和物理实验。
线性和非线性参数分离方法具有特殊的价值,因为它将计算效率与收敛到全局解的可靠性相结合,使其成为解决非线性近似实际问题的首选。