文章目錄
介紹
前面提到了牛頓法,那其實相當於求根的算法。跟一般最小二乘法的區別是,它並沒有顯示的最小二乘目標式子。
下面提到的高斯牛頓法,則要正式引入最小二乘法的目標式子。首先對牛頓法做一次更深入的展開。
牛頓法
牛頓法在用於一元方程求根的時候,只需要做一階泰勒展開,這個時候,用到的是迭代點的導數信息找到下一個迭代點。在多維的情況下面,則用到了梯度信息。在求解的問題的時候,假如初始點選得不好,可能會遇到梯度消失的問題,最後會導致收斂失敗。但這好像是優化算法的一個通病,並非牛頓法的專利。言歸正傳,下面解釋一下牛頓法在四參數數據擬閤中應用。
對於給定的m組數據 ,
稱爲剩餘值,或者叫殘差,偏差,是一個標量,表示剩餘函數,是一個向量。爲待擬合的公式
求解的目標是使得殘差平方最小,如下
牛頓法的第一步是求得,令,再對其做泰勒展開
總共需要對F做二次求導,這裏需要引入jacob矩陣
w 關於r的雅可比矩陣如下
F的梯度信息g(w)
爲標量,爲偏導,或者說梯度,是一個向量,最後得到,
F的海賽陣爲
通常運算量巨大,這部分常用兩種處理,一種是忽略,即小剩餘算法,另外一種是近似,大剩餘算法。
高斯牛頓法忽略了其高階項S(x),相當於目標式子的一階泰勒展開
這個做法其實等同於之前的牛頓法。當殘量比較小時,這種方法比較有效,反之,算法就比較難收斂。另外,從上公式裏面可以看到,的計算要求爲列滿秩,否則求得的結果可能不穩定,導致算法難以收斂。 爲了克服這個問題,其中一個手段是改善矩陣的變態程度。常用的處理就是在方程中加入擾動,也就是嶺迴歸做的事情。從另外一個角度來說,也是加入的2範式懲罰。爲什麼這麼做呢,因爲對於泰勒展開而言,無疑越大,展開式越不準確。由此,便得到了Levenberg-Marquardt算法。
Matlab Code
>> [A,B,C,D] =-10 36.9 1974.7 431.0下面的代碼和之前代碼基本一致,只不過去掉了matlab 的symbolic運算,速度快的飛起
clear;
load census;
x1 = cdate ;
y1 = pop ;
lamda = 0.3;
%init a,b,c,d
d = max(y1)+1;
a = min(y1)-0.1;
y2 = log((y1-d)./(a-y1));
x2 = log(x1);
[curve2,gof2] = fit(x2,y2, 'poly1');
b = -curve2.p1;
c = exp(curve2.p2/b);
%newton
for k = 1:1:1000
fy = [];
JacobiMatrix = ones(length(x1),4);
w=[a,b,c,d];
[res,R,fit] = evaluateFit(y1,x1,w);
if R>0.997
return;
end
for i = 1:1:length(x1)
fy(i,:) = d+(a-d)/(1+(x1(i)/c)^b);
JacobiMatrix(i,1) = calc_pA(x1(i),a,b,c,d);
JacobiMatrix(i,2) = calc_pB(x1(i),a,b,c,d);
JacobiMatrix(i,3) = calc_pC(x1(i),a,b,c,d);
JacobiMatrix(i,4) = calc_pD(x1(i),a,b,c,d);
end
delta_w = inv((JacobiMatrix)'*(JacobiMatrix))*JacobiMatrix'*(y1-fy);
%update a b c d
a = a +lamda*delta_w(1);
b = b+lamda*delta_w(2);
c = c +lamda*delta_w(3);
d= d +lamda*delta_w(4);
end
function [res,R2,fit] = evaluateFit(y,x,w)
fit = getFittingValue(x,w);
res = norm(y-fit)/sqrt(length(fit));
yu = mean(y);
R2 = 1 - norm(y-fit)^2/norm(y - yu)^2;
end
function fit = getFittingValue(x,w)
len = length(x);
fit = ones(len,1);
for i = 1:1:len
fit(i) = hypothesis(x(i),w);
end
end
function val = hypothesis(x,w)
a = w(1);b= w(2);c= w(3);d= w(4);
val = d+(a-d)/(1+(x/c)^b);
end
function val = calc_pA(x,A,B,C,D)
val = 1/((x/C)^B + 1);
end
function val = calc_pB(x,A,B,C,D)
val = -(log(x/C)*(A - D)*(x/C)^B)/((x/C)^B + 1)^2;
end
function val = calc_pC(x,A,B,C,D)
val = (B*x*(A - D)*(x/C)^(B - 1))/(C^2*((x/C)^B + 1)^2);
end
function val = calc_pD(x,A,B,C,D)
val = 1 - 1/((x/C)^B + 1);
end