【機器學習】線性模型與嶺迴歸

上一節中,學習了k-NN模型,用一句話來總結它的特點就是:近朱者赤,近墨者黑。

本節將開始涉及線性模型相關的概念與模型。

線性模型是在實踐中廣泛使用的一類模型,它利用輸入特徵的線性函數進行預測。所以,線性模型非常的耿直

備註:mgleran中的數據是用來展示的,不與機器學習的sklern模塊相重疊。

安裝mgleran請使用pip install mglearn命令。

# 在學習之前,先導入這些常用的模塊
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import mglearn

認識線性模型

對於迴歸問題,線性模型預測的一般公式如下:

y = w[0]*x[0]+w[1]*x[0]+...+w[p]*x[p]

這裏 x[0] 到 x[p] 表示單個數據點的特徵, w 和 b 是學習模型的參數, y 是模型的預測結果。對於單一特徵的數據集,公式如下:

y = w[0]*x[0]+b

類似於實踐學到的:

y = ax+b

也就是說,w[0]就是斜率,b是截距。對於有更多特徵的數據集,w 包含沿每個特徵座標軸的斜率。或者,你也可以將預測的響應值看作輸入特徵的加權求和,權重由 w 的元素給出(可以取負值)。

下列代碼可以在一維wave數據集上學習參數w[0]和b,也就是ax+b的線性結果。

mglearn.plots.plot_linear_regression_wave()
w[0]: 0.393906  b: -0.031804

從該模型可以看出,w[0] 在0.4左右,而b比0稍微小一點。

總結:用於迴歸的線性模型可以表示這樣的迴歸模型:對單一特徵的預測結果是一條直線,兩個特徵時是一個平面,或者在更高維度(即更多特徵)時是一個超平面。

從上圖中可發現,線性模型與k-NN的迴歸模型比較起來,似乎準確率沒有那麼高。但如果數據是多維度的,數量也非常龐大,線性模型將會給出比較完美的擬合。

不同的線性模型之間的區別僅在於如何從訓練數據中學習參數w和b,以及如何控制模型複雜度。

認識線性迴歸模型

線性迴歸,又稱普通最小二乘法,是迴歸問題最簡單也最經典的線性方法。

線性迴歸尋找參數 w 和 b,使得對訓練集的預測值與真實的迴歸目標值 y 之間的均方誤差最小。均方誤差是預測值與真實值之差的平方和除以樣本數。線性迴歸沒有參數,這是一個優點,但也因此無法控制模型的複雜度。

# 從 skleran 中導入線性模型模型 LinearRegression
from sklearn.linear_model import LinearRegression
# 導入數據分割模塊 train_test_split
from sklearn.model_selection import train_test_split

# 導入線性迴歸數據
X, y = mglearn.datasets.make_wave(n_samples=60)
# 將數據打亂,將分成訓練集與測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
# 對訓練集數據進行訓練
lr = LinearRegression().fit(X_train, y_train)

線性模型的“斜率”參數(w,也叫作權重或係數)被保存在coef_屬性中,而偏移或截距(b)被保存在intercept_屬性中:

print('查看模型的斜率:', lr.coef_)
print('查看模型的截距:', lr.intercept_)
查看模型的斜率: [0.39390555]
查看模型的截距: -0.031804343026759746

敲黑板:intercept_是一個浮點數;而coef_是一個NumPy數組,每個元素對應一個輸入特徵。這裏因爲只有一個輸入特徵,因此coef_中只有一個元素。

接下來,查看一下訓練集與測集的性能:

print('訓練集精度:', lr.score(X_train, y_train))
print('測試集精度:', lr.score(X_test, y_test))
訓練集精度: 0.6700890315075756
測試集精度: 0.65933685968637

這個評估結果不是很好,說明模型在訓練集和測試集上都存在欠擬合的情況。這是因此,此處提供的是二維的簡單數據。如果是在高維度的數據上,線性模型將變得更加的強大,此時則可能有過擬合的可能。

接下來,看一下LinearRegression在更復雜的數據集上的表現——波士頓房價數據集,該數據集擁有506個樣本和105個導出特徵。

# 導入波士頓房價數據
X, y = mglearn.datasets.load_extended_boston()

# 將數據分爲訓練集與測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# 對訓練集數據進行訓練
lr = LinearRegression().fit(X_train, y_train)

然後再查看一下模型在訓練集與測試集上的分數:

print('訓練集評估分數:', lr.score(X_train, y_train))
print('測試庥評估分數:', lr.score(X_test, y_test))
訓練集評估分數: 0.9523526436864238
測試庥評估分數: 0.6057754892935623

結果顯示,在訓練集的精度很高,而在測試集的精度則比較低,造成這種情況的原因是因爲在訓練集得出的模型存在近擬合的情況,因此無法更好的適應新的數據。

因此我們應該試圖找一個可以控制複雜複雜度的模型,標準線性迴歸最常用的替代方法之一就是嶺迴歸

認識嶺迴歸

嶺迴歸爲何會成爲標準線性迴歸的替代之一呢?

嶺迴歸也是一種用於迴歸的線性模型,因此它的預測公式與普通最小二乘法相同。但在嶺迴歸中,對係數 w 的選擇不僅要在訓練數據上得出好的預測結果,而且還要擬合附加線束——即希望係數儘量小。

直觀上來看,這意味着每個特徵對輸出的影響應儘可能的小(即斜率很小),同時仍給出很好的預測結果。這種線束是所謂的正則化的一個例子。正則化是指對模型做顯示約束,以避免過擬合。嶺迴歸的這種正則化被稱爲L2正則化

嶺迴歸在 liner_model.Ridge 中實現。來看一下它在波士頓房價的上效果如何。

# 導入嶺迴歸模塊
from sklearn.linear_model import Ridge

ridge = Ridge().fit(X_train, y_train)
print('訓練集評估分數:', ridge.score(X_train, y_train))
print('測試庥評估分數:', ridge.score(X_test, y_test))
訓練集評估分數: 0.8860578560395836
測試庥評估分數: 0.7527139600306947

結果顯示,Ridge 在訓練庥上的分數要低於 LinearRegression, 在測試數據集上的表現比較優秀。

Ridge 是一種約束更強的模型,所以更不容易過擬合。

複雜度更小的模型意味着在訓練集上的性能更差,但泛化性能更好。

由於Ridge的泛化能力更好,所以在這裏應該選擇Ridge模型。

通過設置alpha參數來控制模型的簡單性和訓練性能

在前面的例子中,我們用的是默認的參數 alpha=1.0。它的最取值取決於具體的數據集。

增大 alpha 會使得係數更加趨向於0,從而降低訓練集性能,但可能會提高泛化性能。

例如:

ridge10 = Ridge(alpha=10).fit(X_train, y_train)
print('訓練集評估分數:', ridge10.score(X_train, y_train))
print('測試庥評估分數:', ridge10.score(X_test, y_test))
訓練集評估分數: 0.7883461511233251
測試庥評估分數: 0.6358967327447731

減小 alpha 的值,可以讓係數受到的限制更小。對於非常小的 alpha 值,係數幾乎沒有受到限制,將得到一個與 LinearRegression 類似的模型:

ridge01 = Ridge(alpha=0.1).fit(X_train, y_train)
print('訓練集評估分數:', ridge01.score(X_train, y_train))
print('測試庥評估分數:', ridge01.score(X_test, y_test))
訓練集評估分數: 0.9285782082010736
測試庥評估分數: 0.7717933688844973

不同取值的alpha所對應的斜率變化是怎樣的?

# 畫出默認alpha參數的ridge模型的斜率分佈點
plt.plot(ridge.coef_, 's', label='Ridge alpha=1')
# 畫出alpha=10參數的ridge模型的斜率分佈點
plt.plot(ridge10.coef_, '^', label='Ridge alpha=10')
# 畫出alpha=0.1參數的ridge模型的斜率分佈點
plt.plot(ridge01.coef_, 'v', label='Ridge alpha=0.1')
# 畫出LinearRegression模型的斜率分佈點
plt.plot(lr.coef_, 'o', label='LinearRegression')

# 設置橫座標標籤
plt.xlabel('Coefficient index')
# 設置y座標標籤
plt.ylabel('coefficient magnitude')
# 按照lr斜率集的寬度在0軸畫一條水平線
plt.hlines(0, 0, len(lr.coef_))
# 設置y軸的範圍
plt.ylim(-25,25)
# 顯示圖例
plt.legend()
plt.show()

以上的圖例可以方便對不同的alpha係數與斜率的關係做出一個總結:

alpha=10對應的斜率集分佈點大部分都集中在0軸附近。說明alpha越大,對於係數的約束更強。

alpha值固定,改變訓練數據量,模型的性能將如何表現?

這裏有個現成的圖示,y軸爲模型的評估分數,x軸爲訓練集數據的數量,分別列出了Ridge的訓練集表現與測試集的表現,LinearRegression模型的訓練集的表現和測試集的表現。

mglearn.plots.plot_ridge_n_samples()

通過上圖,發現,訓練集的分數普遍要高於測試集,而約束後的嶺迴歸的訓練集分數比標準迴歸的訓練集分數要低,但嶺迴歸在測試集的分數要比標準迴歸在測試集的分數高。並且,從上圖還看出,嶺迴歸隨着數據的增加,學到的東西趙來趙多,而標準迴歸模型在最後才追趕上嶺迴歸,這完全是數據量的功勞。

所以還能得出結論:如果數據量足夠大,模型的線束將變得不那麼重要。

另一個現象是,從測試集的分數來看,線性迴歸的性能隨着數據的增加,性能一直在下降。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章