基于梯度下降法的——线性回归拟合
點擊“小詹學Python”,選擇“置頂”公眾號
重磅干貨,第一時間送達
本文轉載自數據分析挖掘與算法,禁二次轉載
閱讀本文需要的知識儲備:
高等數學
運籌學
Python基礎
引出梯度下降
對于,線性回歸問題,上一篇我們用的是最小二乘法,很多人聽到這個,或許會說:天殺的最小二乘法,因為很多人對它太敏感了。是的,從小到大,天天最小二乘法,能不能來點新花樣。這里就用數學算法——梯度下降,來解決,尋優問題。
當然了,我們的目標函數還是:
在開始之前,我還是上大家熟知常見的圖片。
梯度下山圖片(來源:百度圖片)
找了好久,我選了這張圖片,因為我覺得這張圖片很形象:天氣驟變,一個人需要快速下山回家,但是他迷路了,不知道怎么回家,他知道自己家位于這座山海拔最低處。環顧四周,怎么樣最快下山回家呢。他個子一定(假設1.8m大個子吧),每次邁步子為平時走路最大步長了,哈哈!(假設保持不變),要往哪個方向走才能使得:每邁出一步,自己下降的高度最大呢?只要每步有效下降高度最大,我們完全有理由相信,他會最快下山回家。
所以:他會告訴自己,我每次要找一個最好的下山方向(有點像“貪心”)。
其實,這個圖還反映了另外一個問題,對于有多個極值點的情況,不同的初始出發點,梯度下降可能會陷入局部極小值點。就像一句古詩:不識廬山真面目,只緣身在此山中!這時候,就需要多點隨機下山解決。當然了,解決線性回歸問題的梯度下降是基于誤差平方和,只有二次項,不存在多峰問題。
梯度下降的理論基礎
我們都現在都知道這個人的任務是什么了:每次要找一個最好的下山方向。數學微分學告訴我們:其實這里的方向就是我們平時所說的:方向導數,它可以衡量函數值沿著某個方向變化的快慢,只要選擇了好的方向(導數),就能快速達到(最大/最小值)。
(1)、梯度的定義
這里還是擺一個公式吧,否則看著不符合我的風格。方向導數定義就不扯遠了,那是個關于極限的定義。這里給出三元函數梯度定義公式:
顯然,讓沿著與梯度方向,夾角為0或者180°時函數值增減最快。
其實,每個多元函數在任一點會有一個梯度。函數在某一點沿著梯度方向,函數值是變化最快的。這里就不過多證明了。
(2)、步長的求法
其實,我們可以設定一個指定步長。但是,這個指定步長到底設為多大合適。眾所周知,過大會導致越過極小值點;過小在數據量大時會導致迭代次數過多。所以我們需要一套理論可以來科學得計算步長。保證在步長變換過程中,盡管有時可能會走回頭路,但總體趨勢是向駐點逼近。
這里簡單說一下,假設在圖中一點沿著梯度方向存在二階偏導數,就可以泰勒展開到平方項,進而對這個關于步長的函數求導數,導函數零點就是此時最佳步長。詳細可以參見運籌學推導。我盡量少寫公式,多說明,哈哈。
用到的公式主要是步長lambda公式如下:
說明:下三角f表示梯度,海賽矩陣,X1,X2這里表示各個變量(這里是兩個),對于連續函數,偏導數不分先后,所以不要算兩遍,后面寫程序會用到!這樣每走一步,都會重新設置步長,與定步長相比,是不是更加智能了?
下降停止標志:梯度趨于0,或者小于給定的eps。
有了這些理論基礎后,編程實現就容易多了,下面就編程實現了。
線性關系呢。最著名的當數最小二乘法了,很多人都知道。
梯度下降的Python實現
這里用的與上一片一樣的數據。
(1)、用到的函數:
不同點的梯度函數,海賽矩陣函數,迭代主函數
這里用到的比如點乘函數,在第一篇《基于最小二乘法的——線性回歸擬合(一)》里面有我是放在一個腳本里面的,所以這里沒有寫兩次,你們可以把兩個腳本放在一起是沒有問題的。
程序代碼:
2#返回梯度向量
3def?dif(alpha,beta,x,y):
4???dif_alpha?=?-2*sum(err(alpha,beta,x,y))
5???dif_beta?=?-2*dot(err(alpha,beta,x,y),x)
6???return(dif_alpha,dif_beta)
7#返回海賽矩陣
8def?hesse(x):
9???return([[2*len(x),2*sum(x)],[2*sum(x),2*dot(x,x)]])
10#計算lambda
11def?lam(x1,x2):
12???s1?=?dot(x1,[x2[0][0],x2[1][0]])
13???s2?=?dot(x1,[x2[0][1],x2[1][1]])
14???return(dot(x1,x1)/dot([s1,s2],x1))
15#導入數學、隨機數模塊
16import?math
17import?random
18def?grad(x,y):
19???#設置最大計算次數
20???n_max?=?100
21???k?=?0
22???error_?=?0.001
23???alpha,beta?=?random.random(),random.random()
24???#計算梯度向量
25???d_f?=?dif(alpha,beta,x,y)
26???while(math.sqrt(dot(d_f,d_f))>error_?and?k<n_max):
27??????h?=?hesse(x)
28??????lamb?=?lam(d_f,h)
29??????alpha,beta?=?[alpha-lamb*d_f[0],beta-lamb*d_f[1]]
30??????d_f?=?dif(alpha,beta,x,y)
31??????k+=1
32???else:
33??????return(alpha,beta,k,math.sqrt(dot(d_f,d_f)))
34alpha,beta,k,error?=?grad(x,y)
35print('
*------------梯度下降-----------*')
36print('系數為:',alpha,beta)
37print('梯度下降擬合次數為:',k)
38print('梯度為:',error)
39print('誤差為:',error_total(alpha,beta,x,y))
40R_square?=?r_square(alpha,beta,x,y)
41print('R方:',R_square)
42if(R_square>0.95):
43???print('在0.05置信水平下,該線性擬合不錯!')
44else:
45???print('在0.05置信水平下,該線性擬合效果不佳!')
46#可視化
47plt.figure(2)
48plt.scatter(x,y,marker?=?'*',color?=?'b')
49plt.xlabel('x?label')
50plt.ylabel('y?label')
51plt.title('Linear?Fit')
52plt.plot(x,[alpha+beta*x_i?for?x_i?in?x],color?=?'r')
53plt.show()
54
55print('
#-------------多個初始點下山---------------#')
56for?i?in?range(10):
57???alpha,beta,k,error?=?grad(x,y)
58???R_square?=?r_square(alpha,beta,x,y)
59??print('系數為:',alpha,beta,'
誤差為:',error_total(alpha,beta,x,y),'
R方:',R_square)
60???if(R_square>0.95):
61??????print('在0.05置信水平下,該線性擬合不錯!')
62???else:
63??????print('在0.05置信水平下,該線性擬合效果不佳!')
64???print('*********************************************')
(2)、結果
*------------梯度下降-----------*
系數為:2.1672851935 2.5282506525292012
梯度下降擬合次數為:5
梯度為:1.2745428915606112e-05
誤差為:9.898083702910405
R方:0.9558599578256541
在0.05置信水平下,該線性擬合不錯!
擬合圖如下
2系數為:2.167285891989479 2.528250598680116
3誤差為:9.898083702904094
4R方:0.9558599578256822
5在0.05置信水平下,該線性擬合不錯!
6*********************************************
7系數為:2.167282336941068 2.5282508727544775
8誤差為:9.898083702990858
9R方:0.9558599578252953
10在0.05置信水平下,該線性擬合不錯!
11*********************************************
12系數為:2.167285928067579 2.5282505958987773
13誤差為:9.898083702903905
14R方:0.9558599578256831
15在0.05置信水平下,該線性擬合不錯!
16*********************************************
17系數為:2.1672811054772247 2.528250967694748
18誤差為:9.898083703052635
19R方:0.9558599578250199
20在0.05置信水平下,該線性擬合不錯!
21*********************************************
22系數為:2.1672836911979947 2.528250768347593
23誤差為:9.898083702941747
24R方:0.9558599578255144
25在0.05置信水平下,該線性擬合不錯!
26*********************************************
27系數為:2.1672838440861364 2.5282507565614916
28誤差為:9.898083702937456
29R方:0.9558599578255335
30在0.05置信水平下,該線性擬合不錯!
31*********************************************
32系數為:2.1672853294236947 2.5282506420502253
33誤差為:9.898083702908751
34R方:0.9558599578256615
35在0.05置信水平下,該線性擬合不錯!
36*********************************************
37系數為:2.1672857750441694 2.5282506076959184
38誤差為:9.898083702904778
39R方:0.9558599578256792
40在0.05置信水平下,該線性擬合不錯!
41*********************************************
42系數為:2.16728609101821 2.5282505833364226
43誤差為:9.89808370290327
44R方:0.9558599578256859
45在0.05置信水平下,該線性擬合不錯!
46*********************************************
47系數為:2.1672842715049874 2.528250723609833
48誤差為:9.898083702926757
49R方:0.9558599578255812
50在0.05置信水平下,該線性擬合不錯!
51*********************************************
當然了,這里多個初始點隨機梯度下降不需要,以后對于多元多峰函數這是有必要的
結果分析
2系數為:2.1672851935?2.5282506525292012
3梯度下降擬合次數為:5
4梯度為:1.2745428915606112e-05
5誤差為:9.898083702910405
6R方:0.9558599578256541
7在0.05置信水平下,該線性擬合不錯!
可以對比最小二乘法與梯度下降誤差,我們猜測肯定是梯度下降誤差大一些,因為最小二乘法基于函數極值點求法肯定是全局最優的,梯度下降由于隨機原因與步長可能是靠近最優,哈哈!在有多個極值點的情況下可能是局部最優解。
2
3系數為:2.6786542252575067?2.538861110659364
4
5誤差為:6.8591175428159215
6
7R方:0.9696451619135048
8
9在0.05置信水平下,該線性擬合不錯!
10
11*------------梯度下降-----------*
12
13系數為:2.1672851935?2.5282506525292012
14
15梯度下降擬合次數為:5
16
17梯度為:1.2745428915606112e-05
18
19誤差為:9.898083702910405
20
21R方:0.9558599578256541
22
23在0.05置信水平下,該線性擬合不錯!
可以看出,梯度為:1.2745428915606112e-05,已經接近0了,跟據實際精度會有不同。顯然,梯度下降這里不存在局部極值點問題,只能是步長邁過去了,但這個點一定是靠近最優解的,誤差非常小。
總結
以上是生活随笔為你收集整理的基于梯度下降法的——线性回归拟合的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 走在前沿的弄潮儿,怎能不会Git的那些奇
- 下一篇: 如何使用Python玩转PDF各种骚操作