机器学习-最小二乘拟合

本文介绍了Levenberg-Marquardt算法,一种解决非线性最小二乘问题的方法,结合了梯度下降法和高斯-牛顿法。文中提供了Python和MATLAB的实现示例,并详细阐述了算法原理和评估指标。通过代码展示了如何使用lsqcurvefit、nlinfit和自定义函数进行非线性拟合,并进行了模型评估和误差分析。
摘要由CSDN通过智能技术生成

0.前言
解决非线性问题的方法:
在这里插入图片描述
最小二乘算法:https://www.mathworks.com/help/optim/ug/least-squares-model-fitting-algorithms.html

这里主要记录Levenberg-Marquardt算法学习笔记!

1.Levenberg-Marquardt算法介绍
基本原理:
在这里插入图片描述
在这里插入图片描述
计算当C最小时对应的函数参数。

  • Levenberg-Marquardt(LM)是一种用于解决非线性最小二乘问题的算法,当通过最小化数据点与函数之间误差的平方和来拟合参数化函数到一组测量数据点时,就会出现最小二乘问题。
  • Levenberg-Marquardt曲线拟合方法实际上是两种最小化方法的结合:梯度下降法( gradient
    descent)和高斯-牛顿法(Gauss-Newton)。
  • 在梯度下降法中,通过在最陡下降方向更新参数来减小误差的平方和。在高斯-牛顿法中,通过假设最小二乘函数是局部二次函数,并求出二次函数的最小值来减小误差的平方和。
  • 评估指标——卡方误差chi-squared error criterion:
    在这里插入图片描述
    在这里插入图片描述
    图片来源:https://msulaiman.org/onewebmedia/LM%20Method%20matlab%20codes%20and%20implementation.pdf

2.Levenberg-Marquardt算法实现-python
最小二乘实现方法:
在这里插入图片描述
python实现方法:https://mmas.github.io/least-squares-fitting-numpy-scipy

scipy.optimize.leastsq(func, x0, args=(), Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-08, xtol=1.49012e-08, gtol=0.0, maxfev=0, epsfcn=None, factor=100, diag=None)
from scipy.optimize import leastsq
def func(x):
    return 2*(x-3)**2+1
leastsq(func, 0)

non-linear least squares fit:

def residual(p, x, y):
    return y - f(x, *p)

p0 = [1., 8.]
popt, pcov = optimize.leastsq(residual, p0, args=(x, y))

print popt

yn = f(xn, *popt)

plt.plot(x, y, 'or')
plt.plot(xn, yn)
plt.show()

3.Levenberg-Marquardt算法实现-MATLAB
(1)LM算法原理:https://blog.csdn.net/waitingwinter/article/details/106142276

(2)LM算法实现:Matlab

(3)非线性拟合:MATLAB

rng('default');%将 rand、randi 和 randn 使用的随机数生成器的设置重置为其默认值。保证结果重复。
% 生成数据
len = 1000;
x = linspace(0.1, 300, len)';
y = 300*exp(-x/5) + 10;
% 添加噪声
y_noise = y + 20*randn(len, 1);
% 调用 lsqcurvefit
func = @(p, x) p(1)*exp(-x/p(2)) + p(3);
% 选择合适的初始值
p0 = [100, 2 1];
p = lsqcurvefit(func, p0, x, y_noise)

linespace函数:np.linspace(a,b,c)用于创建一个等差序列的向量,向量值是[a,b]之间均匀分布的c个实数。
在这里插入图片描述
拟合结果:

% 拟合结果
y_fit_lsq = func(p, x);
% 调用 nlinfit
pp = nlinfit(x, y_noise, func, p0)

nlinfit函数beta = nlinfit(X,Y,modelfun,beta0)
使用 modelfun 指定的模型,返回一个向量,其中包含 Y 中的响应对 X 中的预测变量的非线性回归的估计系数。它使用迭代最小二乘估计来估计系数,初始值由 beta0 指定。

绘图:

figure;
plot(x, y_noise, '.', 'LineWidth', 2);
hold on
plot(x, y_fit_lsq, 'LineWidth', 2);
plot(x, y_fit_nlin, 'LineWidth', 2);
hold off
legend('原始数据', '拟合数据-lsqcurvefit', '拟合数据-nlinfit');

结果展示:
在这里插入图片描述
LM算法实现:

p1 = LSFittingExpFree(x, y_noise)
fit1 = func(p1, x);
plot(x, fit1, 'LineWidth', 2);

%%Levenberg_Marquardt LS Fitting
function result = LSFittingExpFree(x, y)
% Levenberg_Marquardt LS Fitting
% 按列排
x = x(:);
y = y(:);
M = length(x);
% Least Squares Minimization 
rng('default');
% 初始值
a = sqrt(rand);
b = sqrt(rand);
c = sqrt(rand);
% 变量个数
nParam = 3;
% 残差
r = y - (a^2 * exp(-x / b^2) + c^2);
% 目标函数
f = r'*r;   
% 正则化因子初值
lambda = 1;     
% 迭代次数
it = 0;         
% 更新标记
updateFlag = true;                  
 % 最大迭代次数
maxIter = 100;    
% 迭代计算
while it < maxIter
    it = it + 1;
    if updateFlag
        Ja = 2 * a * exp(-x / b^2);
        Jb = 2 * a^2 * x .* exp(-x / b^2) / b^3;
        Jc = 2 * c * ones(M, 1);
        J = [Ja, Jb, Jc];
        g = -2 * J' * r;
        H = 2 * (J'*J);
    end
    Hess = H + lambda * eye(nParam);
    s = -Hess \ g;
    a1 = a + s(1);
    b1 = b + s(2);
    c1 = c + s(3);
    r1 = y - (a1^2 * exp(-x / b1^2) + c1^2);
    f1 = r1'*r1;
    fdr = (f - f1) / f;
    if fdr > 0
        a = a1;
        b = b1;
        c = c1;
        f = f1;
        r = r1;
        lambda = 0.1 * lambda;
        updateFlag = true;
    else
        lambda = 10 * lambda;
        updateFlag = false;
    end
    if max(abs(s)) < 1e-6
        disp(['达到收敛条件,迭代次数:' num2str(it)]);
        break;
   elseif it == maxIter
        disp('达到最高迭代次数,可能不收敛;');
    end
end
result = [a^2, b^2, c^2];
end

在这里插入图片描述

代码来源:https://zhuanlan.zhihu.com/p/388676905

完整代码:lsqcurvefit、LSFittingExpFree、nlinfit、lsqnonlin

% 保证结果可重复
rng('default');
% 生成数据
len = 1000;
x = linspace(0.1, 300, len)';
y = 300*exp(-x/5) + 10;
% 添加噪声
y_noise = y + 20*randn(len, 1);
% 调用 lsqcurvefit
func = @(p, x) p(1)*exp(-x/p(2)) + p(3);
%lsqnonlin
funl = @(p,x,y_noise) p(1)*exp(-x/p(2)) + p(3)- y_noise;
% 选择合适的初始值
p0 = [100, 2 1];
p = lsqcurvefit(func, p0, x, y_noise)
options.Algorithm = 'levenberg-marquardt';
% options = optimoptions(@lsqnonlin,'Algorithm','trust-region-reflective');
[p2,resnorm,residual] = lsqnonlin(funl,p0,[],[],options,x,y_noise)
% 拟合结果
y_fit_lsq = func(p, x);
% 调用 nlinfit
pp = nlinfit(x, y_noise, func, p0)

y_fit_nlin = func(pp, x);
p1 = LSFittingExpFree(x,y_noise)
fit1 = func(p1, x);
fit2 = funl(p2,x,y_noise);

figure;
plot(x, y_noise, '.', 'LineWidth', 2);
hold on
plot(x, y_fit_lsq, 'LineWidth', 2);
plot(x, fit1, 'LineWidth', 2);
plot(x, y_fit_nlin, 'LineWidth', 2);
plot(x, fit2+y_noise, 'LineWidth', 2);
hold off
legend('原始数据', '拟合数据-lsqcurvefit','拟合数据-LSFittingExpFree','拟合数据-nlinfit','拟合数据-lsqnonlin');

%%Levenberg_Marquardt LS Fitting
function result = LSFittingExpFree(x, y)
% Levenberg_Marquardt LS Fitting
% 按列排
x = x(:);
y = y(:);
M = length(x);
% Least Squares Minimization 
rng('default');
% 初始值
a = sqrt(rand);
b = sqrt(rand);
c = sqrt(rand);
% 变量个数
nParam = 3;
% 残差
r = y - (a^2 * exp(-x / b^2) + c^2);
% 目标函数
f = r'*r;   
% 正则化因子初值
lambda = 1;     
% 迭代次数
it = 0;         
% 更新标记
updateFlag = true;                  
 % 最大迭代次数
maxIter = 100;    
% 迭代计算
while it < maxIter
    it = it + 1;
    if updateFlag
        Ja = 2 * a * exp(-x / b^2);
        Jb = 2 * a^2 * x .* exp(-x / b^2) / b^3;
        Jc = 2 * c * ones(M, 1);
        J = [Ja, Jb, Jc];
        g = -2 * J' * r;
        H = 2 * (J'*J);
    end
    Hess = H + lambda * eye(nParam);
    s = -Hess \ g;
    a1 = a + s(1);
    b1 = b + s(2);
    c1 = c + s(3);
    r1 = y - (a1^2 * exp(-x / b1^2) + c1^2);
    f1 = r1'*r1;
    fdr = (f - f1) / f;
    if fdr > 0
        a = a1;
        b = b1;
        c = c1;
        f = f1;
        r = r1;
        lambda = 0.1 * lambda;
        updateFlag = true;
    else
        lambda = 10 * lambda;
        updateFlag = false;
    end
    if max(abs(s)) < 1e-6
        disp(['达到收敛条件,迭代次数:' num2str(it)]);
        break;
   elseif it == maxIter
        disp('达到最高迭代次数,可能不收敛;');
    end
end
result = [a^2, b^2, c^2];
end

结果对比:
在这里插入图片描述
在这里插入图片描述
4.Levenberg-Marquardt模型评估
(1)模型评估方法:如lsqnonlin函数中,可以输出resnorm — Squared norm of the residualresidual — Value of objective function at solution

(2)利用卡方检验Chi-Square Test方法来评估模型:

  • 卡方检验,也称χ 2检验,是检验两个变量之间有没有关系。
  • 卡方检验基本思想:以卡方分布为基础,计算观察值和期望值之间的偏离程度。

卡方检验、t检验和方差分析的区别:https://blog.csdn.net/symoriaty/article/details/100178446
(3)卡方检验(x2检验chi-square test)计算方法:
方法一:四格表资料的x2检验
检验的基本公式为:
在这里插入图片描述
A为实际数;T为理论数;
通过查x2值表求P值,判断两者相关性。

方法二:近似法
计算公式:
在这里插入图片描述

(4)误差分析(来自论文:The Levenberg-Marquardt method for nonlinear least squares
curve-fitting problems)
在这里插入图片描述
在这里插入图片描述

参考资料:
论文:The Levenberg-Marquardt method for nonlinear least squares curve-fitting problems
https://msulaiman.org/onewebmedia/LM%20Method%20matlab%20codes%20and%20implementation.pdf

PPT:Data Modeling and Least Squares Fitting 2
https://www.cs.princeton.edu/courses/archive/fall11/cos323/notes/cos323_f11_lecture08_lsq2

PPT:Numerical Optimization using the Levenberg-Marquardt Algorithm
https://mads.lanl.gov/presentations/Leif_LM_presentation_m.pdf

python实现方法-Least squares fitting with Numpy and Scipy:https://mmas.github.io/least-squares-fitting-numpy-scipy

非线性回归中的Levenberg-Marquardt算法理论和代码实现:https://zhuanlan.zhihu.com/p/349953779;代码:https://github.com/manfrezord/MediumArticles/blob/main/LM-Algorithm.ipynb

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值