1. 程式人生 > >機器學習->監督學習->線性迴歸(LASSO,Ridge,SGD)

機器學習->監督學習->線性迴歸(LASSO,Ridge,SGD)

本篇博文主要總結線性迴歸,線性迴歸雖然簡單,但是卻是很重要,我將沿著以下幾個主題總結

  • 最小二乘法
  • 使用極大似然估計來解釋最小二乘
  • 這裡寫圖片描述的解析式的求解過程
  • 線性迴歸的複雜度懲罰因子(LASSO,Ridge)
  • 梯度下降法
  • 實戰

最小二乘法

線性迴歸,線性是指回歸方程在空間中表現為直線形式,其決策邊界是線性的.迴歸在數學上來說是給定一個點集,能夠用一條曲線去擬合之,如果這個曲線是一條直線,那就被稱為線性迴歸,

基本形式:這裡寫圖片描述

給定資料集”線性迴歸”試圖學得一個線性模型以儘可能地預測實際輸出值.這個不斷學習的過程實際上就是不斷調整這裡寫圖片描述的過程。

然而有一個問題,在這個學習過程中如何評價衡量他學習的效果?因此我們需要定義一個損失函式

,來衡量學習過程中他的效果。

均方誤差是迴歸任務中最常用的效能度量,因此我們可以試圖讓均方誤差最小化.

cost Function:
這裡寫圖片描述

學習的目標:
這裡寫圖片描述

均方誤差有非常好的幾何意義,類似與常用的歐幾里得距離.基於均方誤差最小化的進行模型求解方法稱為”最小二乘法“(least square method),線上性迴歸中,最小二乘法就是找到一條直線,使所有樣本到直線的距離之和最小.

使用極大似然估計來解釋最小二乘

這裡寫圖片描述

上面公式中這裡寫圖片描述表示第i個樣本真實的標籤資料,這裡寫圖片描述表示線性迴歸模型對第i個樣本預測出的標籤資料,這裡寫圖片描述表示擾動,即對於第i個樣本的預測值與真實值的誤差。

誤差這裡寫圖片描述是獨立同分布的,根據中心極限定理

,誤差這裡寫圖片描述服從均值為0(一般而言,如果誤差存在,那麼誤差大於0和小於0的部分可以近似抵消掉),方差為某定值這裡寫圖片描述的高斯分佈。

似然函式
上面說了誤差服從高斯分佈,那麼可得:

這裡寫圖片描述

再求最大似然函式:
這裡寫圖片描述

我們要求出這裡寫圖片描述最大值,可以忽略一些定值,經過稍微的推導,可得求上式最大值等價於求下面公式的最小值:

這裡寫圖片描述

這樣我們就通過了最大似然估計來解釋了最小二乘估計的由來,其實最小二乘估計就是假定誤差服從高斯分佈,認為樣本是獨立,使用最大似然估計就能得出的結論。

這裡寫圖片描述的解析式的求解過程

將M個N維樣本組成矩陣X:

  • X的每一行對應一個樣本,共M個樣本(measurements)
  • X的每一列對應樣本的一個維度,共N維(regressors)
  • 還有額外的一維常數項,全為1

那麼目標函式:

這裡寫圖片描述

梯度:

這裡寫圖片描述

關於矩陣如何求導請看我的另外一篇博文機器學習–>矩陣和線性代數裡面相關內容。

那麼可得引數這裡寫圖片描述的解析解為:
這裡寫圖片描述

若X為可逆矩陣,則有:
這裡寫圖片描述

因此可以定義這裡寫圖片描述為矩陣X的偽逆(或者說廣義逆)這裡寫圖片描述
由此可以推出:這裡寫圖片描述,那麼矩陣X的偽逆怎麼求呢?可以利用SVD分解:
對於m*n的矩陣X,若它的SVD分解為:這裡寫圖片描述,有關SVD分解詳細說明請看我的另外一片博文機器學習–>矩陣和線性代數裡面相關內容。

這裡寫圖片描述不可逆或者為了防止過擬合,增加這裡寫圖片描述擾動得:
這裡寫圖片描述

可以如下的簡便記憶:
這裡寫圖片描述

線性迴歸的複雜度懲罰因子(LASSO,Ridge)

線性迴歸的目標函式為:

這裡寫圖片描述

為了防止引數這裡寫圖片描述過大,我們可以在目標函式後面加上約束項,例如可以這裡寫圖片描述這裡寫圖片描述是一個任意的定值,我們直接認為為0,利用拉格朗日乘子法,在目標函式後面加上這裡寫圖片描述,這個就是LASSO迴歸,Ridge迴歸同理,只是約束項變成其平方形式。

那麼加上不同的正則項來防止過擬合:

Ridge:在目標函式後加上L2正則項

這裡寫圖片描述

LASSO:在目標函式後加上L1正則項

這裡寫圖片描述

ELastic Net:L1正則項與L2正則項混合使用

這裡寫圖片描述

那麼在目標函式後面加上正則項,正則項就是關於這裡寫圖片描述的某個函式,要使目標函式最小,那麼正則項很小,就是這裡寫圖片描述很小是個前提,這就限制了引數這裡寫圖片描述的大小,也就限制了模型的複雜程度,有效的防止過擬合。

我們在訓練一個線性模型時,這個模型越簡單越好,就是希望引數這裡寫圖片描述向量越稀疏越好,也就是希望訓練出的模型,引數向量裡面0越多越好。那麼在上面加上的L1正則項可以達到這個效果,L1正則化可以使一些不重要的引數變為0。

對比L1正則化和L2正則化,來看看為什麼L1正則化能使引數變得稀疏。

這裡寫圖片描述

這裡假設目標函式裡面只有兩個引數這裡寫圖片描述,那麼原始的目標函式,即不帶正則項的目標函式為上面一圈圈的等高線,不斷的取次優點,直到與約束項的圖形有交點。可以看出LASSO的正則項是一個凹的四邊形,即上圖的左圖,目標函式與L1的約束圖形交點肯定在一個座標軸上,那麼另外一個座標軸(特徵)就可以忽略了,這就達到了一個降維或者是特徵選擇的作用。對比L2正則項,L2的約束項圖形是一個圓形,其目標函式與其交點不大可能出現在座標軸上,這就達不到降維或者特徵選擇的作用。

梯度下降法

在實際情景中,這裡寫圖片描述往往不是滿秩矩陣,則就不存在逆矩陣.或者當特徵維度非常大時求逆運算時間開銷很大,導致這種直接求解不具備可行性.

於是我們要用一種逼近的辦法來求解引數:梯度下降法.
梯度下降法一般流程:

  1. 首先對引數賦值,這個值可以是隨機的,也可以這裡寫圖片描述讓是一個全零的向量.
  2. 改變這裡寫圖片描述的值,使其損失函式按照梯度下降的方向進行減少,這個方向其實就是減少最快的方向
    這裡寫圖片描述
    這時目標函式是關於引數這裡寫圖片描述的函式,需要不斷的沿著引數的梯度方向下降,才能到達最低點。

    這裡寫圖片描述

  3. 不斷重複2)步驟,使其誤差在給定範圍內.

梯度方向:
這裡寫圖片描述

這裡需要注意:當我們以損失函式進行引數估計時(例如線性迴歸裡面的最小二乘估計),因為是求損失函式最小時的引數(是一個不斷下降地逼近最低值),故採用梯度下降法,當我們用最大似然函式進行引數估計時,是求似然函式最大時對應的引數(是一個不斷上升地逼近最高值),那麼這時時梯度上升法。其實道理都是一樣,只是前面正負號的問題。

批量梯度下降演算法(GD):每次迭代拿出所有樣本來更新引數
這裡寫圖片描述
凸函式肯定能利用批量梯度下降法達到全域性最優值(前提選擇合適學習速率)

隨機梯度下降演算法(SGD):每次迭代隨機拿出一個樣本來更新引數
這裡寫圖片描述
有時候隨機梯度下降法比起批量梯度下降法更不容易陷入區域性最優

折中:mini-batch(mini-batchGD):每次迭代隨機拿出一部分樣本來更新引數
這裡寫圖片描述

現在一般把mini-batchGD直接叫做SGD。

一步步更新w,b,一步步的迭代,那麼這個更新迭代的過程什麼時候結束呢?通常採用以下辦法來判斷什麼時候停止更新迭代

1)定義一個最大迭代步數,當迭代次數大於等於這個最大迭代步數時,停止迭代
2)定義一個最小誤差,當你更新得到的w,b代入到均方誤差中得出的誤差小於定義的最小誤差,則停止迭代。

從泰勒公式解釋隨機梯度下降法

我們知道對於一個連續函式h(x),在可導的某點處x0,都可以展開近似,逼近h(x)

這裡寫圖片描述

顯然,當x 很接近x0 時:
這裡寫圖片描述

同理多變數的泰勒展開式:
這裡寫圖片描述

回到機器學習中的lossFunction,我們假設該lossFunction 只有兩個引數決定,分別是θ1,θ2。則loss 的等高線可如下:

這裡寫圖片描述

那麼在點(a,b) 處,我們可以利用泰勒展式來逼近L(θ)
這裡寫圖片描述

這裡寫圖片描述

注意:上式中的約等於號要成立,則點(θ1,θ2) 必須在點(a,b) 附近,兩點距離越近越相等。

好了,我們得到了L(θ) 的公式,希望能minimizeloss
這裡寫圖片描述

上式中的sθ 無關,可以忽略,那麼有:

L(θ)=u(θ1a)+v(θ2b)
將其看成向量內積的形式,則在最小化loss 時有:

這裡寫圖片描述

(\theat1,θ2) 取向量(u,v) 的反方向,但是其向量長度不能太大,我們需要保證其距離向量(a,b) 較近的地方,這樣其上面的約等於號才能成立。

最後需要注意一點:線性迴歸可以是對樣本非線性的,只要是對引數這裡寫圖片描述線性即可。
例如:這裡寫圖片描述也是線性迴歸模型。

實戰

根據以上所學的我們來做一道題:
預測2014年南京市的房價,下面給出其歷史資料:
Year X=[2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013]
Price Y=[2.000,2.500,2.900,3.147,4.515,4.903,5.365,5.704,6.853,7.971,8.561,10.000,
11.280,12.900]
這裡寫程式碼片
#coding:utf-8
import numpy as np


def geData():
    X=[0,1,2,3,4,5,6,7,8,9,10,11,12,13]
    Y=[2.000,2.500,2.900,3.147,4.515,4.903,5.365,5.704,6.853,7.971,8.561,10.000,11.280,12.900]
    points=np.array((X,Y)).T
    return points

def errors(w,b,points):
    totalError=0
    for i in range(0,len(points)):
        x=points[i,0]
        y=points[i,1]
        totalError+=(y-(w*x+b))**2
    return totalError

def step_gradient(b_current,w_current,points,alpha):
    b_gradient=0
    w_gradient=0
    N=float(len(points))
    for i in range(0,len(points)):
        x=points[i,0]