天天看點

線性回歸算法梳理(從理論到示例)

1、機器學習的一些概念

  • 有監督、無監督:

    有監督機器學習又被稱為“有老師的學習”,所謂的老師是名額簽。監督學習就是最常見的分類(注意和聚類區分)問題,通過已有的訓練樣本(即已知資料及其對應的輸出)去訓練得到一個最優模型(這個模型屬于某個函數的集合,最優表示某個評價準則下是最佳的),再利用這個模型将所有的輸入映射為相應的輸出,對輸出進行簡單的判斷進而實作分類的目的。也就具有了對未知資料分類的能力。

    無監督機器學習被稱為“沒有老師的學習”,無監督相比于有監督,輸入資料沒有被标記,也沒有确定的結果。樣本資料類别未知,需要根據樣本間的相似性對樣本集進行分類(聚類,clustering)試圖使類内差距最小化,類間差距最大化。通俗點将就是實際應用中,不少情況下無法預先知道樣本的标簽,也就是說沒有訓練樣本對應的類别,因而隻能從原先沒有樣本标簽的樣本集開始學習分類器設計。

  • 泛化能力:
    泛化能力(generalization ability)是指一個機器學習算法對于沒有見過的樣本的識别能力。我們也叫做舉一反三的能力,或者叫做學以緻用的能力。舉個例子,國小生先通過學習十以内的加減乘除,知道什麼是四則運算和怎麼具體去算數,以後遇到百以内或者千以内的數字也知道怎麼去做四則運算。我們隻教會他十以内的運算,他自己就能推廣到百以内或者千以内的運算,這種能力就是泛化能力。
  • 過拟合與欠拟合(方差和偏差以及各自的解決辦法):

    過拟合:國小生學習四則運算,老師教過1+1=2,那麼學生隻記住了1+1=2,以後做題的時候碰到1+1知道答案是2,但是碰到10+10就不知道怎麼計算答案,學生隻是死記硬背1+1的答案是2,沒了解四則運算的規律,不會推廣到10+10,也就是泛化能力非常低,同時我們也把這種現象叫做過拟合(over-fitting)了。

    過拟合是一種分類器會發生的現象,而泛化能力可以了解為對分類器的一種性能的評價,過拟合表現為算法模型的高方差,模型訓練時的結果很好,但是在預測時結果不好。

    産生過拟合的原因:模型的複雜度太高,比如:網絡太深;過多的變量(特征);訓練資料非常少。

    避免過拟合的方法有很多:(1)盡量減少特征的數量、(2)early stopping、(3)資料集擴增、(4)dropout、(5)正則化包括L1、L2、(6)清洗資料。

    欠拟合under-fitting)是和過拟合相對的現象,可以說是模型的複雜度較低,沒法很好的學習到資料背後的規律。就好像開普勒在總結天體運作規律之前,他的老師第谷記錄了很多的運作資料,但是都沒法用資料去解釋天體運作的規律并預測,這就是在天體運作資料上,人們一直處于欠拟合的狀态,隻知道記錄過的過去是這樣運作的,但是不知道道理是什麼。

    欠拟合指的是模型不夠複雜,沒有很好地捕捉到資料特征,不能夠很好地拟合資料,對應模型的高偏差。

    解決欠拟合可以從尋找更好的特征(具有代表性的)和使用更多的特征(增大輸入向量的次元)。具體的方法:1、添加更多的特征項(比如上下文特征、位置特征等);2、添加多項式特征(例如将線性模型通過添加二次項或者三次項使模型泛化能力更強);3、減少正則化參數,正則化的目的是用來防止過拟合的,但是現在模型出現了欠拟合,則需要減少正則化參數。

  • 交叉驗證:

    一個交叉驗證将樣本資料集分成兩個互補的子集,一個子集用于訓練(分類器或模型)稱為訓練集(training set);另一個子集用于驗證(分類器或模型的)分析的有效性稱為測試集(testing set)。利用測試集來測試訓練得到的分類器或模型,以此作為分類器或模型的性能名額。得到高度預測精确度和低的預測誤差,是研究的期望。為了減少交叉驗證結果的可變性,對一個樣本資料集進行多次不同的劃分,得到不同的互補子集,進行多次交叉驗證。取多次驗證的平均值作為驗證結果。

    用交叉驗證的目的是為了得到可靠穩定的模型。

2、線性回歸的原理

線性回歸為何叫線性?實際上,像在處理Google的股票統計資料時,我們使用線性回歸是在這堆資料所在的N維空間中找到一條線來描述這些資料的規律,是以才叫線性回歸。這個過程稱為拟合,這條線成為拟合線。

這條拟合線上的某個資料點或多或少都會偏離實際統計的值。實際統計資料和拟合線對應資料的差叫殘差。很明顯,殘差可以反映模型的預測誤差。

但是殘差有正有負的,不友善計算。而且實際運用中我們不需要關注殘差的正負,因為正負并不能描述誤差的大小程度。為了降低計算複雜性,我們使用這個內插補點的平方進行計算。你可能會想到,內插補點的平方不是把內插補點給改了嗎,沒關系嗎?答案是:資料确實變了,但沒影響。因為我們真正使用的是殘差的絕對值,用它描述誤差大小的程度,而對這個絕對值進行平方後有同樣的效果,畢竟 y = ∣ x ∣ {y = |x|} y=∣x∣ 與 y = x 2 {y = x^2} y=x2有同樣的單調性。

結合上述平方的想法,為了讓預測更加準确,我們應該選擇一條線,能夠使得線上每個點與實際資料的殘差平方的總和最小。這樣的線才能叫最佳拟合線。直覺了解,線性回歸其實就是這麼一條直線。

3、線性回歸的目标函數、損失函數(代價函數)

線性回歸試圖學得 f ( x i ) = w ∗ x i + b {f(x_i) = w*x_i + b} f(xi​)=w∗xi​+b(目标函數)使得 f ( x i ) ≃ y i {f(x_i)\simeq y_i} f(xi​)≃yi​,如何确定 w {w} w和 b {b} b呢?關鍵在于如何衡量 f ( x ) {f(x)} f(x)與 y {y} y之間的差别。

均方誤差是回歸任務中常用的性能度量,是以我們試圖讓均方誤差(損失函數,或代價函數)最小化,即

( w ∗ , b ∗ ) = a r g m i n ( w , b ) ∑ i = 1 m ( f ( x i ) − y i ) 2 = a r g m i n ( w , b ) ∑ i = 1 m ( y i − w x i − b ) 2 {(w^*,b^*)=argmin_{(w,b)} \sum_{i=1}^{m}(f(x_i)-y_i)^2=argmin_{(w,b)} \sum_{i=1}^{m}(y_i-wx_i-b)^2} (w∗,b∗)=argmin(w,b)​∑i=1m​(f(xi​)−yi​)2=argmin(w,b)​∑i=1m​(yi​−wxi​−b)2

均方誤差有非常好的幾何意義,它對應了常用的歐幾裡得距離(歐氏距離),基于均方誤差最小化來進行模型求解的方法稱為“最小二乘法”。

線上性回歸中,最小二乘法就是試圖找到一條直線,使得所有樣本到直線上的歐氏距離之和最小。

求解 w {w} w和 b {b} b使 ∑ ( w , b ) = ∑ i = 1 m ( y i − w x i − b ) 2 {\sum_{(w,b)}=\sum_{i=1}^{m}(y_i-wx_i-b)^2} ∑(w,b)​=∑i=1m​(yi​−wxi​−b)2最小化的過程,稱為線性回歸模型的最小二乘“參數估計”。這裡暫不推廣到其它模型(多元線性回歸和邏輯回歸)。

注意: 我們為了求導計算友善,往往将損失函數寫成下面的形式:

J ( w ) = J ( w 0 , w 1 ) = 1 2 m ∑ i = 1 m ( h ( x i ) − y i ) 2 {J(w)=J(w_0,w_1)=\frac {1}{2m} \sum_{i=1}^{m}(h(x^i)-y^i)^2} J(w)=J(w0​,w1​)=2m1​∑i=1m​(h(xi)−yi)2,

其中, h ( x i ) − y i {h(x^i)-y^i} h(xi)−yi是預測值和實際值的差,是以損失(成本代價)就是預測值和實際值的差的平方的平均值,之是以乘以 1 2 {\frac {1}{2}} 21​是為了計算友善,這個函數也被稱為均方差方程。有了損失函數,就可以精确地測量模型對訓練樣本拟合的好壞程度。

4、優化方法(梯度下降法、牛頓法等)

有了目标函數(預測函數),也可以精确地測量預測函數對訓練樣本的拟合情況,我們要怎樣求解模型的參數的值呢?這時,梯度下降算法就派上用場了。

梯度下降法

我們希望能找到 w {w} w使得 J ( w ) {J(w)} J(w)達到最小,于是我們可以使一個搜尋算法,初始化 w {w} w為一個任意值,在疊代過程中不斷地更新 w {w} w使得 J ( w ) {J(w)} J(w)更小,直到收斂為止(可以認為 J ( w ) {J(w)} J(w)不再改變)。下面我們來考慮梯度下降算法,它先給 w {w} w一個初始化值,然後通過下面公式來更新 w {w} w。

w j : = w j − η   ∂ J ( w ) ∂ w j {w_j:= w_j-\eta \ \frac{\partial J(w)}{\partial w_j}} wj​:=wj​−η ∂wj​∂J(w)​,其中 j = 0 , 1 , 2 , . . . , n {j=0,1,2,...,n} j=0,1,2,...,n

上式中, η {\eta} η是學習率,為了了解上面的算法,我們需要推導一下偏微分部分,推導過程中我們隻考慮一個樣例 ( x , y ) {(x,y)} (x,y),然後隻需要把所有的樣例加起來就可以了。

∂ J ( w ) ∂ w j = 1 2 ∂ ( h w ( x ) − y ) 2 ∂ w j = ( h w ( x ) − y ) ∂ ( ∑ i = 0 n w i x i − y ) ∂ w j = ( h w ( x ) − y ) x j {\frac{\partial J(w)}{\partial w_j}=\frac{1}{2} \frac{\partial (h_w(x)-y)^2}{\partial w_j} = (h_w(x)-y)\frac{\partial (\sum_{i=0}^{n}w_ix_i-y)}{\partial w_j}=(h_w(x)-y)x_j} ∂wj​∂J(w)​=21​∂wj​∂(hw​(x)−y)2​=(hw​(x)−y)∂wj​∂(∑i=0n​wi​xi​−y)​=(hw​(x)−y)xj​

對于單獨的第i個樣本,更新規則為:

w j : = w j − η ( h w ( x i ) − y i ) x j i {w_j:= w_j-\eta (h_w(x^{i})-y^i)x_{j}^{i}} wj​:=wj​−η(hw​(xi)−yi)xji​,其中 j = 0 , 1 , 2 , . . . . , n {j=0,1,2,....,n} j=0,1,2,....,n

當有m個樣本時,更新規則為:

w j : = w j − η ∑ i = 1 m ( h w ( x i ) − y i ) x j i {w_j:= w_j-\eta \sum_{i=1}^{m}(h_w(x^{i})-y^i)x_{j}^{i}} wj​:=wj​−η∑i=1m​(hw​(xi)−yi)xji​,其中 j = 0 , 1 , 2 , . . . , n {j=0,1,2,...,n} j=0,1,2,...,n

上式每次疊代将所有樣本考慮進來更新 w {w} w,這種方法叫做批量梯度下降。梯度下降容易陷入一個局部的最優解,事實上 J ( w ) {J(w)} J(w)是一個凸函數,是以沒有所謂的局部最優解,它隻有一個全局最優解,凸函數的這種性質非常好用。

之後又出現了随機梯度下降(或增量梯度下降)SGD,該算法每一個樣例都更新了 w {w} w一次,當m很大的時候,批量梯度下會很耗時,通常,随機梯度下降比批量梯度下降要快很多,然而它可能永遠達不到最小值,并在最小值附近震蕩,而實際上這種近似最小值已經夠了。在樣本量比較大的情況下,随機梯度下降比梯度下降更實用。

牛頓法

牛頓法的思想就是通過疊代來找到函數的零點。牛頓法是二階收斂,梯度下降是一階收斂,牛頓法通常比梯度下降算法收斂速度要快,隻需要更少的疊代次數就能獲得最小值。然而一次牛頓疊代要比一次梯度下降更昂貴,因為它需要計算 H e s s a n {Hessan} Hessan矩陣并且求它的逆,這将花費不少時間。但是當參數個數 n {n} n不是太大時,總體來說速度還是要快很多。

5、線性回歸的評估名額

在預測任務中,給定樣例集 D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x m , y m ) } {D=\{(x_1,y_1),(x_2,y_2),...,(x_m,y_m)\}} D={(x1​,y1​),(x2​,y2​),...,(xm​,ym​)},其中 y i {y_i} yi​是示例 x i {x_i} xi​的真實标記。要評估學習器 f {f} f的性能,就要把學習器預測結果 f {f} f與真實标記 y {y} y進行比較。

回歸任務最常用的性能度量(評估名額)是“均方誤差”(mean squared error,MSE):

E ( f ; D ) = 1 m ∑ i = 1 m ( f ( x i ) − y i ) 2 {E(f;D)=\frac{1}{m} \sum_{i=1}^{m}(f(x_i)-y_i)^2} E(f;D)=m1​∑i=1m​(f(xi​)−yi​)2。

拓展一些分類任務中常用的性能度量,以後再來作詳細補充。

錯誤率與精度;查全率、查準率與 F 1 {F_1} F1​值; R O C {ROC} ROC與 A U C {AUC} AUC;代價敏感錯誤率與代價曲線等。

6、sklearn參數詳解(示例)

在scikit-learn裡,LinearRegression類實作了線性回歸算法。我們這一節使用scikit-learn自帶地波士頓房價資料集來訓練模型,然後用模型來測算房價。

在sklearn的波士頓房價資料集裡,總共收集了13個特征,具體如下:

  • CRIM:城鎮人均犯罪率
  • ZN:城鎮超過25,000平方英尺的住宅區域的占地比例
  • INDUS:城鎮非零售用地占地比例
  • CHAS:是否靠近河邊,1為靠近,0為遠離
  • NOX:一氧化氮濃度
  • RM:每套房産的平均房間個數
  • AGE:在1940年之前就蓋好,且業主自住的房子的比例
  • DIS:與波士頓市中心的距離
  • RAD:周邊高速公路的便利性指數
  • TAX:每10,000美元的财産稅率
  • PTRATIO:國小老師的比例
  • B:城鎮黑人的比例
  • LSTAT:地位較低的人口比例

    這些名額中可以看出中美文化的一些差異。當然,這個資料是在1993年之前收集的,可能和現在會有差異。實際上一個模型的好壞和輸入特征的選擇是關系密切的。開一下腦洞,如果在中國預測房價,應該收集哪些特征資料?收內建本有多高?特征資料的可獲得性怎麼樣?

    廢話不多說,開始撸代碼。

  • 我們導入資料
from sklearn.datasets import load_boston

boston = load_boston() #加載資料集
X, y = boston.data, boston.target # 獲得資料集X和标簽(真實值)y
print(X.shape) # 看一下資料集的形狀,其輸出為(506,13),表明這個資料集有506個樣本,每個樣本有13個特征。
print(y.shape)

"""
整個訓練樣本放在一個506 * 13的矩陣裡。可以通過X[0]來看一個樣本資料:

"""
print(X[0])

"""輸出:
[6.320e-03 1.800e+01 2.310e+00 0.000e+00 5.380e-01 6.575e+00 6.520e+01
 4.090e+00 1.000e+00 2.960e+02 1.530e+01 3.969e+02 4.980e+00]
"""

boston.feature_names # 檢視這些特征的标簽
"""
array(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
       'TAX', 'PTRATIO', 'B', 'LSTAT'], dtype='<U7')
"""
           
  • 模型訓練
# 在對模型進行訓練之前,我們需要先把資料集分成兩份,以便評估算法的準确性。

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=3)

"""
由于資料集較小,我們隻選取了20%(參數test_size)的樣本作為測試集。
接着,訓練模型并測試模型的準确性評分。
"""
import time
from sklearn.linear_model import LinearRegression

model = LinearRegression()
start = time.clock()
model.fit(X_train, y_train)

train_score = model.score(X_train, y_train)
cv_score = model.score(X_test, y_test)
print("elaspe: {0:.6f}; train_score: {1:0.6f}; cv_score: {2:.6f}".format(time.clock()-start, train_score, cv_score))

"""輸出:
elaspe: 0.063014; train_score: 0.723941; cv_score: 0.794958

我們順便統計了模型的訓練時間,除此之外,統計模型針對訓練樣本的準确性得分(即對訓練樣本拟合的好壞程度)train_score,
還統計了模型針對測試樣本的得分cv_score

從得分情況來看,模型的拟合效果一般,還有沒有辦法來優化模型的拟合效果呢?
"""
           
  • 模型優化
"""
首先觀察一下資料,特征資料的範圍相差比較大,最小的在10的13次方級别,而最大的在10的2次方級别,看來我們需要先把資料進行歸一化處理。
歸一化處理最簡單的方式是,建立線性回歸模型的時候增加normalize=True參數。
model = LinearRegression(normalize=True)

當然,資料歸一化處理隻會加快算法收斂速度,優化算法訓練的效率,無法提升算法的準确性。
怎麼樣優化模型準确性呢?我們回到訓練分數上來,可以觀察到資料針對訓練樣本的評分較低(train_score: 0.723941),
即模型對訓練資料的拟合成本(損失,或者誤差)比較高,這是典型的欠拟合現象。大家可以往上翻一下如何處理欠拟合的辦法:
一是挖掘更多的輸入特征,二是增加多項式特征。這裡我們使用低成本的方案,即增加多項式特征來看看能否優化模型的性能。
增加多項式特征,其實就是增加模型的複雜度。

下面我們寫一個建立多項式模型的函數
"""
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline

def polynomial_model(degree=1):
    polynomial_features = PolynomialFeatures(degree = degree,
                                             include_bias = False)
    linear_regression = LinearRegression(normalize = True)
    pipeline = Pipeline([("polynomial_features", polynomial_features), ("linear_regression", linear_regression)])
    return pipeline
           
"""
接着,我們使用二階多項式來拟合資料。
"""
model = polynomial_model(degree=2)  # 二階多項式

start = time.clock()
model.fit(X_train, y_train)

train_score = model.score(X_train, y_train)
cv_score = model.score(X_test, y_test)
print("elaspe: {0:.6f}; train_score: {1:0.6f}; cv_score: {2:.6f}".format(time.clock()-start, train_score, cv_score))

"""輸出
elaspe: 0.049655; train_score: 0.930547; cv_score: 0.860465

可以看到,訓練樣本分數和測試分數都提高了,看來模型确實得到了優化。我們還可以把多項式改成三階看一下結果。
其實改為三階後,針對訓練樣本的分數達到了1,而針對測試樣本的分數卻為負數,說明這個模型過拟合了。
"""
           

==============================================================

繼續閱讀