線性回歸算法
注:本文所有代碼和數(shù)據(jù)均在個人github下click me
回歸算法一般是針對預(yù)測是連續(xù)的情況下,對于預(yù)測值是離散的,采用的算法是分類算法。線性回歸算法包括很多種變形,這里提到的線性回歸算法是其中的幾種典型算法。在實際應(yīng)用中,我們采用線性算法可以預(yù)測商品的價格,預(yù)測房子的房價等等,雖然線性回歸算法比較簡單,但是在實際中還是有很多的使用的。
在機器學(xué)習(xí)中,我們要緊盯三件事情。第一,算法的損失函數(shù);第二,采用什么求值算法求損失函數(shù)的最小值;第三,算法的評價指標
一般線性回歸算法
一般的線性回歸又叫做最小二乘算法,最小二乘是因為算法的損失函數(shù)是最小二乘的,損失函數(shù)如下:
其中是算法針對數(shù)據(jù)的預(yù)測值,而
是數(shù)據(jù)的真實值,
表示訓(xùn)練數(shù)據(jù)的條數(shù),而
是為了此公式求導(dǎo)方便而加入的。而
是算法的參數(shù),在這里就是線性回歸的權(quán)重值。通過此公式我們可以得到,線性回歸算法的損失函數(shù)就是針對每個樣本計算預(yù)測值和真實值得差,然后將差求平方,之后將全體樣本的差平方相加即得到損失函數(shù)。
針對損失函數(shù),我們有兩種算法可以求取損失函數(shù)的最小值。
梯度下降算法
梯度下降算法的一般形式:
這里寫的是梯度下降算法的標量形式。這個公式描述了梯度下降算法是如何更新算法的參數(shù)的,其中是參數(shù)的更新步長??梢钥吹竭@里的關(guān)鍵是如何求取損失函數(shù)關(guān)于參數(shù)j的偏導(dǎo)數(shù)。
將損失函數(shù)帶入到梯度下降算法,即公式中,并且求導(dǎo),可以得到下式:
我們重復(fù)的使用公式直到達到收斂條件,即可以求得線性回歸算法中的參數(shù)值。
從公式中,可以看到用真實值和預(yù)測值之間的差值來更新參數(shù)值,這種方式或者思想在很多的機器學(xué)習(xí)算法中可以看到,包括深度學(xué)習(xí)的后向傳播算法。同時,可以看到每一次的迭代都要使用整個數(shù)據(jù)集。這種方式叫做批量梯度下降算法。還有一種方式可以求取值,叫做隨機梯度下降算法,算法如下:
從中我們可以看到,隨機梯度下降算法每次采用一個訓(xùn)練樣本取更新所有的參數(shù)值,注意那里的(for every j)。當訓(xùn)練樣本很多時,相比于批量梯度下降算法,隨機梯度下降算法能夠更快的更新算法的參數(shù)值,并且能夠更快的逼近損失函數(shù)的最小值。
代數(shù)解
我們將損失函數(shù)用向量表示,如下所示:
公式中的表示訓(xùn)練數(shù)據(jù)的矩陣。因為損失函數(shù)是凸二次函數(shù),所以只有一個最小值,所以導(dǎo)數(shù)為0的點就是損失函數(shù)的最小值。
具體的推導(dǎo)過程如下(主要利用了矩陣的跡運算):
令導(dǎo)數(shù)等于0,從而得到:
回歸模型的概率解釋
大家想過沒有,為什么在線性回歸模型里面選擇最小二乘作為損失函數(shù)?接下來從概率的角度來解釋選擇最小二乘作為損失函數(shù)的原因。
首先,假設(shè)目標變量和輸入數(shù)據(jù)存入如下的關(guān)系:
這里的是誤差項,包括模型未考慮到影響目標變量的因素和隨機噪聲。
接下來假設(shè),誤差項相互獨立同分布,并且服從高斯分布(即正態(tài)分布)
為什么要假設(shè)誤差項服從高斯分布? 第一是因為采用高斯分布,在數(shù)學(xué)上處理會比較簡單;第二是因為根據(jù)中心極限定理,獨立的隨機變量的和,其總的影響接近高斯分布
誤差項的概率密度函數(shù)為:
根據(jù)公式和公式
,我們可以得出如下結(jié)論:
在公式中,不是隨機變量,而是實際存在的值,雖然我們不知道真實值是多少。
的含義是給定
,參數(shù)設(shè)定為
時,
的概率密度。注意公式中用的分號。
數(shù)據(jù)的概率是由給出的,而總的概率可以看成是在固定
時,關(guān)于
的函數(shù)。換個角度,我們想要將這個函數(shù)明確的看成是關(guān)于
的函數(shù),所以我們將其稱作似然函數(shù),從而我們得到關(guān)于
的似然函數(shù):
似然(likelihood)和概率(probability)實際上是一個東西,但是似然函數(shù)是對參數(shù)
定義的,為了加以區(qū)分,使用了似然這一術(shù)語。我們可以說參數(shù)的似然,數(shù)據(jù)的概率,但不能說數(shù)據(jù)的似然,參數(shù)的概率。
極大似然估計就是選擇,使參數(shù)的似然函數(shù)最大化,也就是選擇參數(shù)使得已有樣本的出現(xiàn)概率最大。
因為是嚴格單調(diào)遞增的,并且對數(shù)函數(shù)也是遞增的,所以取對數(shù),得到的
跟不取對象是一樣的。
對數(shù)似然函數(shù):
最大化似然函數(shù),就是最大化對數(shù)似然函數(shù),即最小化
這個式子剛好是線性回歸算法中采用的損失函數(shù)??偨Y(jié)一下,最小二乘回歸模型剛好就是在假設(shè)了誤差獨立同服從正態(tài)分布后,得到的最大似然估計。同時注意到,正態(tài)分布中的方差的取值對模型并沒有影響。
編程實現(xiàn)
代數(shù)解實現(xiàn)線性回歸算法
def standard_regression(x_arr, y_arr):
"""
這里直接采用代數(shù)解直接求取權(quán)重大小.這里有個條件是xTx的逆必須存在,
如果不存在,則直接返回
:param x_arr:
:param y_arr:
:return:
"""
x_mat = np.mat(x_arr)
y_mat = np.mat(y_arr).T
xTx = x_mat.T * x_mat
if np.linalg.det(xTx) == 0.0:
print("矩陣是奇異的,逆不存在")
return
ws = xTx.I * (x_mat.T * y_mat)
return ws
根據(jù)standard_regression函數(shù)可以直接求取算法的權(quán)重。然后根據(jù)權(quán)重就可以求得數(shù)據(jù)的預(yù)測結(jié)果,這里選擇的數(shù)據(jù)在點我
畫出的圖像如下:

直線為擬合直線,散點是真實值。
隨機梯度下降實現(xiàn)線性回歸
由于代碼篇幅比較長,所以可以直接上我的github上面看。代碼
局部加權(quán)線性回歸算法
每個點都對應(yīng)一個不同的,利用
計算預(yù)測值。
下面我們用剛才介紹的局部加權(quán)線性回歸來擬合一下這個模型,簡單回顧一下過程:
1.用高斯核函數(shù)計算出第i個樣本處,其它所有樣本點的權(quán)重W
2.用權(quán)重w對第i個樣本作加權(quán)線性回歸,得到回歸方程,即擬合的直線方程
3.用剛才得到的經(jīng)驗回歸直線計算出處的估計值
4.重復(fù)一至三步,得到每個樣本點的估計值
同時,從計算公式中,可以看到對于每個點的預(yù)測值,需要利用所有的數(shù)據(jù)樣本進行計算。如果數(shù)據(jù)量比較大,計算量就會是一個大問題。
相比于上面提到線性回歸算法(參數(shù)算法),局部加權(quán)線性回歸算法是非參數(shù)算法。
參數(shù)算法vs非參數(shù)算法
引用地址
參數(shù)算法:
如果我們對所要學(xué)習(xí)的問題有足夠的認識,具備一定的先驗知識,此時我們一般會假定要學(xué)習(xí)的目標函數(shù)f(x)或分布P(y|x)的具體形式。然后,通過訓(xùn)練數(shù)據(jù)集,基于ERM、SRM、MLE、MAP等學(xué)習(xí)策略,可以估計出f(x)或P(y|x)中含有的未知參數(shù)。一旦未知參數(shù)估計完畢,訓(xùn)練數(shù)據(jù)一般來說,就失去其作用了,因為這些估計出來的參數(shù)就是訓(xùn)練數(shù)據(jù)的濃縮。通過這種方式建立起來的模型就是參數(shù)模型。參數(shù)模型的一個很重要的特點是,如果對于模型的假設(shè)正確,那么只需要很少的訓(xùn)練數(shù)據(jù)就可以從假設(shè)空間中學(xué)出一個很好的模型。但是,如果模型的假設(shè)錯誤,那么無論訓(xùn)練的數(shù)據(jù)量有多大,甚至趨于無窮大,學(xué)出的模型都會與實際模型出現(xiàn)不可磨滅的偏差。感知機、邏輯斯特回歸、高斯判別分析、樸素貝葉斯、線性支持向量機都屬于參數(shù)模型。對于神經(jīng)網(wǎng)絡(luò)來說,當固定了隱層的數(shù)目以及每一層神經(jīng)元的個數(shù),它也屬于參數(shù)模型。但由于隱層數(shù)目與每一層神經(jīng)元個數(shù)的不確定性,很多時候,神經(jīng)網(wǎng)絡(luò)都被歸類為半?yún)?shù)模型。
非參數(shù)算法:
當我們對所要學(xué)習(xí)的問題知之甚少,此時我們一般不會對潛在的模型做過多的假設(shè)。在面對預(yù)測任務(wù)的時候,我們通常會用上所有的訓(xùn)練數(shù)據(jù)。例如簡單的核密度估計(KDE)的表達式中,就帶有所有訓(xùn)練數(shù)據(jù)的信息。通過這種方式建立的模型就是非參數(shù)模型。非參數(shù)模型的一個很重要的特點就是:let the data speak for itself. 正因為如此,非參數(shù)模型的存儲開銷、計算開銷都會比參數(shù)模型大的多。但是,由于不存在模型的錯誤假定問題,可以證明,當訓(xùn)練數(shù)據(jù)量趨于無窮大的時候,非參數(shù)模型可以逼近任意復(fù)雜的真實模型。這正是非參數(shù)模型誘人的一點。另外需要說明的一點是,非參數(shù)模型之所以叫做非參數(shù),并不是因為模型中沒有參數(shù)。實際上,非參數(shù)模型中一般會含有一個或多個超參數(shù),外加無窮多個普通的參數(shù)。k近鄰就是典型的非參數(shù)模型。
總結(jié)就是所謂參數(shù)學(xué)習(xí)算法它有固定的明確的參數(shù),參數(shù) 一旦確定,就不會改變了,我們不需要在保留訓(xùn)練集中的訓(xùn)練樣本。而非參數(shù)學(xué)習(xí)算法,每進行一次預(yù)測,就需要重新學(xué)習(xí)一組 , 是變化的,所以需要一直保留訓(xùn)練樣本。
實際使用
這里采用的數(shù)據(jù)跟線性回歸算法采用的相同。選取不同的k值,得到的擬合曲線如下圖:

從圖中可以看到,當k值較小時,對于訓(xùn)練數(shù)據(jù)有很好的擬合效果;當k值較大時(比如取1),對于訓(xùn)練數(shù)據(jù)擬合的效果不是很好。當然這都是針對訓(xùn)練數(shù)據(jù),在實際使用中,我們更關(guān)注的是對于測試數(shù)據(jù)的效果如何。在實際中,我們可以將數(shù)據(jù)進行十倍交叉驗證,選擇最合適的k值。
從高斯公式中,我們從兩個方面看。首先,我們固定k值,那么距離較遠的樣本,其對應(yīng)的權(quán)重相對較小;距離
較近的樣本,其對應(yīng)的權(quán)重相對較大,當x取
時,對應(yīng)的權(quán)重為1。而如果我們固定x(即只看某一特定樣本點),k取值較大時,此樣本點對應(yīng)的權(quán)重相對較大;k取值較小時,此樣本點對應(yīng)的權(quán)重相對較大。所以k可以控制算法選擇
點附近有多少樣本參與計算。
最上面的圖是樣本點,剩下三幅圖都是針對樣本點x=0.5,根據(jù)不同的k值,畫出的x附近樣本的權(quán)重變化??梢钥吹剑攌取0.5時,當計算x=0.5時的預(yù)測值時,幾乎所有的樣本點都包括了;而當k=0.01時,僅僅取了x=0.5附近的點參與計算。如果k值取無窮大,那么w對于所有的點的權(quán)重都是1,那么局部加權(quán)線性回歸就變成了普通的線性回歸算法。
嶺回歸算法(Ridge Regression)
上面介紹的線性回歸算法里面可以看到需要計算的逆,那么如果逆不存在呢?首先思考第一個問題,什么情況下,
的逆不存在呢?
- X本身存在相關(guān)關(guān)系,即非滿秩矩陣。比如其中兩列是具有線性關(guān)系
- 如果特征列多余樣本數(shù)量,那么
也是非滿秩的。
對于逆不存在的情況下,我們需要將原來的線性回歸算法進行處理,使原先無法求逆的變成非奇異的??梢酝ㄟ^縮減的方式來處理這類問題,比如嶺回歸算法和LASSO算法。同時由于能夠調(diào)整算法中權(quán)重的大小,能夠防止線性回歸算法的過擬合問題。
嶺回歸算法損失函數(shù)
通過改變的值,可以使得算法的方差和偏差之間達到平衡,增加
,模型的方差減小而偏差增加。
對損失函數(shù)求取一階導(dǎo)數(shù),并另導(dǎo)數(shù)等于0,求得權(quán)重如下式:
在嶺回歸算法中的選擇對于算法有很大的影響。下圖展示了不同的
的取值對于權(quán)重的影響,因為數(shù)據(jù)有八個特征,所以這里有八個權(quán)重。當
較小時,權(quán)重的值跟采用常規(guī)的線性回歸差不多;而當
較大時,權(quán)重的值都會被調(diào)解的較小。

為了找到合適的值,我們在實踐中往往會采用交叉測試來找到合適的
值。
lasso回歸算法(Least Absolute Shrinkage and Selection Operator)
從嶺回歸算法中,我們可以看到,算法防止過擬合主要是在損失函數(shù)中添加懲罰項。在嶺回歸中,懲罰項如下所示:
而在lasso回歸算法中,懲罰項變成下式:
即將權(quán)重的平方和小于,替換為權(quán)重的絕對值和小于
.進行了這個變化后,能夠?qū)?quán)重縮小到0,而嶺回歸中無法將權(quán)重值縮小到0,只能接近0.
lasso回歸算法損失函數(shù)
我們也可以結(jié)合嶺回歸算法和lasso的損失函數(shù),構(gòu)建新的損失函數(shù)。這就是彈性網(wǎng)絡(luò)(ElasticNet)
逐步向前回歸
LASSO計算復(fù)雜度相對較高,本部分稍微介紹一下逐步向前回歸,他屬于一種貪心算法,給定初始系數(shù)向量,然后不斷迭代遍歷每個系數(shù),增加或減小一個很小的數(shù),看看代價函數(shù)是否變小,如果變小就保留,如果變大就舍棄,然后不斷迭代直到回歸系數(shù)達到穩(wěn)定。代碼如下:
def run_stage():
x_arr, y_arr = load_data_set('./data/abalone.txt')
all_w_001 = stage_wise(x_arr, y_arr, 0.001, 5000)
print(all_w_001)
all_w_01 = stage_wise(x_arr, y_arr, 0.01, 200)
print(all_w_01)
def stage_wise(x_arr, y_arr, eps=0.01, num_iter=100):
"""
forward stagewise regression算法(前向梯度算法)
是一種近似的 lasso算法
:param x_arr:
:param y_arr:
:param eps:每次特征權(quán)重的變化步長
:param num_iter: 迭代次數(shù)
:return:
"""
x_mat = np.mat(x_arr)
y_mat = np.mat(y_arr).T
y_mean = np.mean(y_mat, 0)
y_mat = y_mat - y_mean
x_mean = np.mean(x_mat, 0)
x_var = np.var(x_mat, 0)
x_mat = (x_mat - x_mean) / x_var
m, n = np.shape(x_mat)
ws = np.zeros((n, 1))
ws_best = ws.copy()
return_mat = np.zeros((num_iter, n)) # 保存每次迭代最好的權(quán)重值
for i in range(num_iter):
# print(ws.T)
lowest_error = np.inf
for j in range(n):
for sign in [-1, 1]:
ws_test = ws.copy()
ws_test[j] += eps * sign
y_test = x_mat * ws_test
rss_err = rss_error(y_mat.A, y_test.A) # 將矩陣轉(zhuǎn)為數(shù)組
if rss_err < lowest_error:
lowest_error = rss_err
ws_best = ws_test
ws = ws_best.copy()
return_mat[i, :] = ws.T
return return_mat
逐步回歸算法的主要有點在于他可以幫助人們理解現(xiàn)有的模型并作出改進。當構(gòu)建了一個模型后,可以運行逐步回歸算法找出重要的特征,即使停止那些不重要特征的收集。
總結(jié)
上面提到的這些線性回歸算法,我們應(yīng)該怎么選擇呢?一般來說有一點正則項的表現(xiàn)更好,因此通常你應(yīng)該避免使用簡單的線性回歸。嶺回歸是一個很好的首選項,但是如果你的特征僅有少數(shù)是真正有用的,你應(yīng)該選擇Lasso和彈性網(wǎng)絡(luò)。就像我們討論的那樣,它兩能夠?qū)o用特征的權(quán)重降為零。一般來說,彈性網(wǎng)絡(luò)的表現(xiàn)要比Lasso好,因為當特征數(shù)量比樣例的數(shù)量大的時候,或者特征之間有很強的相關(guān)性時,Lasso可能會表現(xiàn)的不規(guī)律。
參考文檔
- 《吳恩達cs229 課程講義》
- 《機器學(xué)習(xí)實戰(zhàn)》
- 機器學(xué)習(xí)實戰(zhàn)_線性回歸&邏輯回歸(二)