【機器學習基礎】——線性回歸


之前看過一些有關機器學習的基礎資料和視頻,但很多知識點都記不太清了,現在專門開個專題,根據自己的理解將之前學過的進行回顧和整理,可能會引用一些例子和資料,資料主要來源於視頻學習和《統計學習方法》一書,可能對於一些不清楚的問題會翻看一些博客等資料。

本節主要針對線性回歸的原理以及梯度下降求解方法進行回顧。


線性回歸

線性回歸原理

  線性回歸是回歸問題,不同於分類問題,線性回歸的輸出是一個scalar,即一個連續型的數值,即是給定一組數據{(x1,y1),(x2,y2),...,(xN,yN)}對數據進行回歸分析,即對給定的數據進行擬合,找出最適合這組數據的一組參數w,b,從而擬合出方程y=wx+b,如圖所示:

  圖上每個點就是一個數據,最終擬合出的紅色的直線,這里的方程屬於廣義方程,並非簡單的直線方程,后面會進一步解釋。

  既然線性回歸屬於機器學習一種方法,那么按照機器學習的三步走策略:

  (1)給定一個模型及對應的一系列的模型參數(a set of function)

  (2)找到一個衡量每個模型好壞的(goodness of function)

  (3)從眾多模型中選出一個最好的模型出來(training data)

  下面我們結合一個具體的例子,對上面的步驟分別展開進行討論,例子來源於李宏毅老師的機器學習的視頻:

  假設有10只寶可夢,就是10條訓練數據,即屬性分別是血量(hp)、身高(Height),體重(Weight)等,標簽y為進化后的戰斗力(combat pow,cp),我們希望通過這些屬性對進化后的戰斗力cp進行預測,即:

  現在假設cp僅與hp有關,其他的屬性暫時不考慮,即是一個二維的數據集,按照三步走的策略:

第一步a set of function:

  給定一個模型集合,由於是線性回歸,因此在二維空間中就是一條直線:

   這里w,b可以取各種各樣的值,即對應不同的模型,可以是如下這種:

  那么究竟哪種模型是最好的呢,這是我們需要給定一個衡量模型好壞的標准,因此進入

第二步goodness of function:

  通常衡量模型好壞標准使用損失函數Loss Function,其輸入是一個模型f,輸出是這個模型f有不好,那么在線性回歸中,如何定義LossFunction呢:

  通常通過該模型的輸出值與真實值之間的差別有多大作為損失,即平方損失或者絕對值損失兩種,這里采用平方損失,即所有樣本模型預測值與真實值之間差值的平方和,用ˆy表示真實值,f(x)表示模型的預測值,那么損失函數表示為:

  那么我們希望這樣的損失越小越好,即找到一組參數w,b使得L最小,所得的w,b即與真實模型(這么說不恰當)是最接近的,即:

  那么怎樣找到這樣一組參數呢?

第三步training data:

  理論上根據所給定的數據集,窮舉所有模型,依次代入模型,所求的最小的L即為最優參數w,b,但遺憾的模型所可能的取值並不能窮舉。於是梯度下降可以對上述問題進行求解(后面會說為什么梯度下降),利用給定數據集,通過求解L分別w,b的求導,不斷更新w,b朝着L減小的方向變化,直到結果收斂,這個過程就稱之為線性回歸的訓練過程,即每次參數更新都朝着梯度的負方向移動,不斷減小Loss的值,即更新規則為:

   這里η為學習率learning_rate,即每次朝着Loss降低的方向移動的幅度,假設僅有一個參數w時,即Loss關於w的方程,那么上述過程放在圖上即為:

  那么同時考慮w和b時,則就變成了下面這樣:

  這里有個問題,在用gradient descend的時候,當我們每次更新的時候是否一定會使得Loss下降呢?即:

  其實並不是這樣,看下面這張圖:

  參數在更新的過程中,會陷入平原點和鞍點,此時導數幾乎為0,可能不再更新了。

  那么按照上面的算法的結果如何呢?

  通過梯度下降,找到一組參數w=2.7,b=-188.4,然后帶回到模型中,得到這樣的一條直線:

  在訓練集上的均方誤差為31.9,在測試集上的均方誤差為35。顯然,這樣的結果誤差有點大,那么如何讓結果能夠更好呢?也就是說在上面三個步驟中,哪一步可以進一步優化呢?

  首先是模型上,之前選用的是一次模型,那么現在換成二次呢?(注意,這里即使是二次,同樣也是線性模型,相當於利用原先的特征構造出一個新特征出來),即:

  然后按照上面后面兩個步驟依次更新參數w1,w2和b,再次訓練數據集,擬合出一條二次曲線:

   訓練集在該模型的均方誤差為15.4,在測試集上的均方誤差為18.4,可以看到效果變好了,那我們能不能繼續把擬合的曲線變得更復雜呢,即繼續增加xhp的次數,3次方項、4次方項等等:

  那么最終得到如下一組擬合結果:

  結果可以看出隨着模型復雜程度的不斷增加,在訓練集上擬合效果越來越好,但是當模型增加到5次時,在測試集上的擬合效果就壞掉了,從所得到的誤差數據來看:

                                                                                                            

  從數據可以看出,隨着模型復雜度的不斷提高,在訓練集上的誤差越來越小,而在測試集上則是先減小,然后陡增,這種情況稱之為過擬合(overfitting)即:

  上面的過程是只考慮了一個特征,如果將其他特征(weight,height等)考慮進去,並考慮每一個物種的類別,再重新設計模型:

  根據每個類別的樣本(這里的分類其實只是為了理解線性模型而定的,實際中這樣的類別可能在訓練樣本中並不存在,我們可以假想這也是一個特征,特征的不同取值屬於不同的類別),再加上體重xw、身高xh特征,最終得到得到一個模型y,再進行訓練,發現在訓練集上的誤差只有1.9,然而在測試集上為102.3,這仍然是過擬合狀態。

  Tips:上面說到,當特征為2次方、3次方等的時候該模型依舊是一個線性模型,其實高次項相當於是在建模過程中自己構建出來的一個全新的特征,可視作一個新的變量,因此,這樣的模型也是線性模型。

  回到上面,那么模型過擬合,我們該如何解決呢?即通過犧牲一定的在訓練集上的誤差,來減小在測試集上的誤差呢?回到第二步,在度量模型好壞的指標上入手:

正則化

  一種有效解決過擬合的方法就是正則化,即在損失函數中加入一定的代價函數,這種代價函數可以解釋為先驗知識,在優化誤差函數的時候傾向於選擇滿足約束的梯度減少的方向,使最終的解傾向於符合先驗知識(來自於百科)。

  正則化有L1正則和L2正則,這里主要說一下L2正則,后面有時間對正則化進行單獨討論,先看對原損失函數加上L2正則項:

  通常wi越小意味着損失也就越小,結果就越好,前面提到正則項通常解釋為先驗知識,因為在實際情況中,我們認為曲線越光滑則越接近於實際情況,這里的wi就是用來約束擬合結果的光滑程度,擬合結果可以寫作:

  上式可以看出,更小的wi可以使得曲線變得光滑,但也不能過於光滑。從正則化項來看,λ和w二者是呈反比的,即λ越大,則w就越小,就越光滑,當λ的值很小時,其懲罰項值不大,還是會出現過擬合現象,當時λ的值逐漸調大的時候,過擬合現象的程度越來越低,但是當λ的值超過一個閾值時,就會出現欠擬合現象,因為其懲罰項太大,導致w過小,從而丟失太多的特征,甚至一些比較重要的特征。

  那么實際對上面最后一個模型進行訓練時,選取不同λ跟誤差的關系如圖所示:

                                                                                            

關於誤差

  前面說到誤差是樣本的真實值與預測之間差值,其包含了兩部分:偏差和方差,可以想象為打靶,偏差表示偏離靶心的程度,偏離靶心越大說明偏差就越大;而方差表示打靶時所打的那些點的散亂程度,越散亂表示方差越大,如下一張圖可以很好地說明二者的關系:

  對比於打靶,在模型訓練過程中,偏差表示模型對數據集的擬合程度即樣本真實值與預測值之間的偏差,即模型本身的擬合能力,偏差越小說明模型對訓練數據擬合的越好,而方差則表示模型的泛化能力,越小的方差表示模型的泛化能力越強。

舉例說明:

  現有500個樣本,每組樣本有10個,共500組,現用不同的復雜程度的模型對500組樣本分別進行擬合,得若干組含有500組不同的參數和模型,將其畫在一張圖上:

  方差部分:

  可以看到,簡單模型擁有更小的方差,都集中在一起,而當模型變得復雜后,及其散亂,方差變大;同樣,對比不用復雜程度模型的偏差:

  可以看到模型過於簡單,對數據的擬合不足,具有較大的偏差,而復雜的模型能夠更好的擬合數據。

  模型偏差、方差隨着模型復雜度變化如圖:

  可以看出,當模型較為簡單時,偏差大,方差小,而當模型復雜時,偏差減小,方差增大。

  當模型在訓練樣本上具有較大偏差(誤差)時,即模型較為簡單時,不能很好地擬合數據,我們稱之為欠擬合;

  當模型在訓練樣本上具有較小誤差,但在測試集上誤差很大,說明模型過於復雜,方差較大,這時稱之為過擬合(注意,這里兩個條件都要滿足,不能僅因為在測試集上的誤差大就認為是過擬合)。

  那么面對欠擬合和過擬合該怎么辦呢?

  首先是欠擬合,欠擬合的原因是模型過於簡單,因此我們可以考慮一下措施:

  (1)增加模型復雜程度;

  (2)增加更多的特征(其實也是一種增加模型復雜程度);

  (3)減小正則化參數;

  對於過擬合,我們考慮模型過於復雜,因此可以:

  (1)降低模型復雜程度;

  (2)加入正則化;

  (3)減少樣本特征(也是一種降低模型復雜程度);

  (4)增加訓練樣本數量(方差的大小與樣本數量N有關);

  (5)增大正則化參數;

  后面神經網絡還有一些其他方法如dropout、earlystopping等。

關於訓練

  那么再對樣本進行訓練時,我們一般有訓練集和測試集,測試集是為了驗證模型好壞的一個數據集,需要是對模型一個陌生的數據集,訓練后我們不能直接根據測試集去反過來再去調整模型,這樣模型可能會朝着測試集再逐漸優化,使得測試集變成了新的“訓練集”,因此訓練時我們需要從訓練數據中分出一部分數據用戶驗證模型,稱之為驗證集,通過驗證集調整模型參數,比較著名的就是N-fold cross validation,其做法如下:

新增內容:

2.關於局部加權線性回歸

最近看《機器學習實戰》一書時,書中提到一種局部加權線性回歸算法,這里簡單總結一下。

上面線性回歸中一開始說到,當利用一個特征時,我們的擬合效果不好,而采用二次方、三次方項的時候,擬合效果較好,而二次方、三次方項相當於我們自己構造出的新的特征。

那么有時我們並不知道或者說要去嘗試去構造一些新的特征出來,才能更好的擬合數據,如何能使特征的選擇變得不那么重要呢?

同時,如果簡單采用一次項的時候,往往很難表示出數據中的一些細節,如下面一個例子:

可以看到,如果單純僅用線性擬合上面一組數據,並不能很好的反映出數據鋸齒狀的細節。

因此,針對上面兩個問題,局部加權線性回歸能夠解決上面的問題。

所謂局部加權線性回歸,是指在進行數據擬合時,對數據賦予一定的權值,使要擬合的點附近的點的權重增大,而離要擬合的點遠的數據的權重減小,假設x為要預測的點,x(i)為樣本中的某一個點,通常權重的計算方式為:

這個是Gaussian RBF核,類似於SVM中引入核函數的概念。其圖像如下

 可以看到:

也就是說,距離x較近的點x(i)的權重較大,距離x(i)較遠的點的權重較小,甚至消失,式中的τ則控制了權重大小,不同的τ范圍不同:

可以看出,τ決定了哪些數據參與到了訓練中,但是局部加權也有個缺點,就是在每次進行預測時,都會重新調用整個樣本,重新確定參數,因此計算量較大,有點類似KNN。

這種方法通過OLE方法求解,方法如下:

下面看一下實現過程:

#  局部線性回歸
def lwlr(testPoint, xArr, yArr, k=1.0):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    m = np.shape(xMat)[0] # 取矩陣的行數
    weights = np.mat(np.eye((m))) # 創建一個對角矩陣,對角線為1,其他為0
    for j in range(m):             #next 2 lines create weights matrix
        diffMat = testPoint - xMat[j,:]     # 開始計算權值了
        weights[j,j] = np.exp(diffMat*diffMat.T/(-2.0*k**2))
    xTx = xMat.T * (weights * xMat)
    if np.linalg.det(xTx) == 0.0:
        print("矩陣不可逆")
        return
    ws = xTx.I * (xMat.T * (weights * yMat))
    return testPoint * ws
 
def lwlrTest(testArr,xArr,yArr,k=1.0):  #loops over all the data points and applies lwlr to each one
    m = np.shape(testArr)[0]
    yHat = np.zeros(m)
    for i in range(m):
        yHat[i] = lwlr(testArr[i],xArr,yArr,k)
    return yHat

測試數據如圖所示:

 

 測試代碼一下上面的兩個函數:

x, y = loadDataSet('./ex0.txt')
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.scatter(mat(x)[:, 1].flatten().A[0], mat(y).T[:, 0].flatten().A[0])

yHat = lwlrTest(x, x, y, 0.03)
srtind = mat(x)[:, 1].argsort(0)
xsort = mat(x)[srtind][:, 0, :]
ax.plot(xsort[:, 1], yHat[srtind], 'red', linewidth=2)

看下效果:

 

可以看到,這樣的擬合按照數據的“紋路”進行擬合了,就相當於是每次只對於每一小部分數據進行擬合。

加權加權回歸是一種非參數回歸,因為其每次預測都需要重新計算一遍參數,且每次參數都不一樣,沒有固定的參數,所以稱之為非參數模型。

上面就是局部加權線性回歸了,由於其主要是采用的是最小二乘的解析解形式,所以前面沒有說到這一部分內容,這里做一個補充,后面還有所謂的L1正則和L2正則對應的嶺回歸和Lasso回歸,后面進一步補充。


有關線性回歸的內容到這里就基本結束了,其中很多問題在回顧的過程中會有更深刻的理解,由於線性回歸屬於機器學習入門,其實現比較簡單就不作討論了,值得一提的是,線性回歸還有另外一種正規方程解法,對應的sklearn庫中的LinearRegressin的API,本文的梯度下降求解方法則對應着SGDRegressor的API,二者是有區別的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM