非线性最小二乘法曲线拟合

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
具体细节参见代码:

function [beta] = nonLinearSquareFit(X,Y,beta,option)
% X,Y 要拟合的数值对,一维向量/矩阵
% beta - 参数初始值以及输出的参数值,一维向量/矩阵
% option - 优化参数

if nargin < 4
    option.tolFun = 1.0e-8;  % 阈值
    option.tolX = 1.0e-8;    % 阈值
    option.DerivStep = eps^(1/3);  % 
    option.MaxIter = 200;  % 最大迭代次数
end
% X与Y的元素数量必须一致
if numel(X)~=numel(Y)
    error('the length of X must be equal to Y!')
end
X = reshape(X,[numel(X), 1]);
y = reshape(Y,[numel(Y), 1]);
beta = reshape(beta, [numel(beta), 1]);

betatol = option.tolX;
rtol = option.tolFun;
DerivStep = option.DerivStep;
if isscalar(DerivStep)
    DerivStep = repmat(DerivStep, size(beta));
else
    DerivStep = reshape(DerivStep, size(beta));
end
maxiter = option.MaxIter;

% 更新参数的系数
lambda = 0.01; 
sqrteps = sqrt(eps(class(beta)));

yfit = model(X, beta);
% 判断yfit和y是否有NAN
nans = ((isnan(y(:))) | isnan(yfit(:)));
r = y(:) - yfit(:);
r(nans) = [];
p = numel(beta);
sse = r'*r;

zerosp = zeros(p,1,class(r));
iter = 0;

while iter < maxiter
    iter = iter + 1;
    betaold = beta;
    sseold = sse;
    
    J = getjcb(X, betaold, DerivStep, yfit, nans);
    diagJtJ = sum(abs(J).^2, 1);
    Jplus = [J; diag(sqrt(lambda*diagJtJ))];
    rplus = [r; zerosp];
%     Jplus = [J];
%     rplus = [r];
    step = Jplus \ rplus;
%     step1 = solvingEquat(Jplus, rplus);
%     step2 = pinv(Jplus) * rplus;
%     fprintf(2, 'diff step1 = %f\n', step(:) - step1(:));
%     fprintf(2, 'diff step2 = %f\n', step(:) - step2(:));
    beta(:) = beta(:) + step(:);
    
    yfit = model(X, beta);
    fullr = y(:) - yfit(:);
    r = fullr(~nans);
    sse = r'*r;
    
    if sse < sseold
        lambda = max(0.1*lambda,eps);
    else
        while sse > sseold
            lambda = 10*lambda;
            if lambda > 1e16
                break
            end
            Jplus = [J; diag(sqrt(lambda*sum(J.^2,1)))];
            step = Jplus \ rplus;
            beta(:) = betaold(:) + step;
            yfit = model(X, beta);
            fullr = y(:) - yfit(:);
            r = fullr(~nans);
            sse = r'*r;
        end
    end
    
    if norm(step) < betatol*(sqrteps+norm(beta))
        break
    elseif abs(sse-sseold) <= rtol*sse
        break
    end
end

function [J] = getjcb(X, beta, DerivStep, yfit, nans)
    % get jocabian
    beta = reshape(beta, [1, numel(beta)]);
    [numThetaRows, numParams] = size(beta);
    
    delta = zeros(numThetaRows, numParams, 'double');
    J = zeros(numel(yfit), numParams, 'double');
    for i = 1:numParams
        delta(:,i) = DerivStep(i) * beta(:,i);
        deltaZero = (delta(:,i) == 0);
        if any(deltaZero)
            nTheta = sqrt(sum(beta(deltaZero,:).^2, 2));
            delta(deltaZero,i) = DerivStep(i) * (nTheta + (nTheta==0));
        end
        thetaNew = beta + delta;
        yplus = model(X, thetaNew);
        yplus(nans) = [];
        dy = yplus(:) - yfit(:);
        J(:,i) = dy./delta(1,i);
        delta(:,i) = 0;
    end
    


function [Y] = model(X,beta)
    % 待拟合的曲线
    Y = beta(1)*exp(-X/beta(2)) + beta(3);

测试代码如下:

%% name: testNonLinearSquare.m
%% test nlinfit
    X = [100,144,167,200,300,400,600,1000];
    Y = [103,100,98,97,94,93,91,90];

    func = inline('beta(1)*exp(-x/beta(2))+beta(3)','beta','x');
    beta0 = [10 144 1]';  % 初始参数值,其值关系到拟合的效果
    beta1 = nlinfit(X,Y,func,beta0);

    [beta2] = nonLinearSquareFit(X,Y,beta0);

    xi = (50 : 1100);
    yi1 = beta1(1)*exp(-xi/beta1(2)) +beta1(3);
    yi2 = beta2(1)*exp(-xi/beta2(2)) +beta2(3);
    diff = sum(yi2-yi1)
    
    figure
    plot(X,Y,'.', xi,yi1,'r-', xi,yi2,'b-');
    radStr{1} = 'y vs x data1';
    radStr{2} = 'nlinfit';
    radStr{3} = 'nonLinearSquareFit';
    legend(radStr);
    xlabel('X');
    ylabel('Y');
    title('curve fitting');

输出的拟合曲线为:
在这里插入图片描述

  • 11
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
最小二乘法是一种数学优化技术,用于通过最小化误差的平方和,寻找数据的最佳函数匹配。在Python中,可以使用NumPy和SciPy库来实现最小二乘法曲线拟合。 以下是一个使用最小二乘法拟合曲线的Python代码示例: ``` import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit # 自定义函数 def func(x, a, b, c, d): return -a * x - b + c - d # 定义x、y散点坐标 x = np.array([0, 4, 8, 12, 16, 20, 24, 28]) y = np.array([0.1, 0.255, 0.15, 0.31, 0.1, 0.3, 0.2, 0.3]) # 非线性最小二乘法拟合 popt, pcov = curve_fit(func, x, y) # 获取拟合系数 a = popt<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [使用Python最小二乘法拟合曲线的代码实现](https://blog.csdn.net/Roy_70/article/details/123853693)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [最小二乘法拟合python实现](https://blog.csdn.net/qq_43619847/article/details/126014168)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Python-最小二乘法曲线拟合](https://blog.csdn.net/weixin_39657094/article/details/110349318)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值