(本文所使用的Python庫和版本號: Python 3.5, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )git
在個人上一篇文章(【火爐煉AI】機器學習003-簡單線性迴歸器的建立,測試,模型保存和加載)中,已經詳細的講解了簡單線性迴歸器的構建和測試,簡單線性迴歸器的優點在「簡單」,運行速度快,但缺點也在於「簡單」,過於簡單以致於難以擬合不少複雜的數據集。github
好比,若是數據集中存在一些遠離大部分數據點的異常點,以下圖所示,那麼簡單線性迴歸器就會獲得比較差的迴歸直線,這是由於線性迴歸器要擬合數據集中全部的數據點,也包括這些異常點,因此異常點每每會把模型「帶到溝裏去」。dom
面對這樣的數據集,該怎麼樣獲得正確的擬合直線了?可使用正則化項的係數做爲閾值來消除異常值的影響,這個方法被稱爲嶺迴歸。機器學習
嶺迴歸是專門用於數據集中存在誤差數據(異常點)的迴歸分析方法,本質上是對普通最小二乘法進行改良,放棄最小二乘法的無偏性,以損失部分信息,下降精度爲代價得到迴歸係數更符合數據集實際狀況的迴歸方法,因此嶺迴歸對於有誤差數據的數據集的擬合要明顯強於使用最小二乘法的線性迴歸模型。函數
線性迴歸模型能夠用下列公式表示:post
線性迴歸模型所使用的損失函數爲:學習
經過最小二乘法求解獲得的最優解爲:測試
前面提到,嶺迴歸的本質是對最小二乘法進行改良,簡單來講,嶺迴歸就是在矩陣XTX上加一個I,加入的這一部分至關於引進了誤差性。因此嶺迴歸的損失函數和最優解分別爲:優化
在代碼層面上,嶺迴歸器的構建方式和線性迴歸器的構建方法同樣,只是建立一個linear_model. Ridge ()對象,而不是linear_model.LinearRegression()迴歸器對象,以下部分代碼所示。spa
# 嶺迴歸器的構建
from sklearn import linear_model
ridge_regressor=linear_model.Ridge(alpha=0.02,fit_intercept=True,max_iter=10000)
# 構建嶺迴歸器對象,使用的誤差係數爲alpha=0.02
ridge_regressor.fit(whole_x,whole_y) # 使用嶺迴歸器進行訓練
# 使用訓練完成的嶺迴歸器預測數值
y_train_predict=ridge_regressor.predict(whole_x)
plt.scatter(whole_x,whole_y)
plt.plot(whole_x,y_predict,'-b')
plt.plot(whole_x,y_train_predict,'-r')
複製代碼
########################小**********結###############################
1,圖中藍色線條爲使用線性迴歸器獲得的結果,紅色爲使用alpha爲0.02時獲得的擬合直線,兩個重合了,貌似是alpha取值過小所致。
2,alpha參數控制嶺迴歸器的複雜程度,但alpha趨近於0時,嶺迴歸器就至關於普通的最小二乘法(從圖中能夠看出,alpha=0.02時,兩條直線幾乎重合),因此,若是但願該嶺迴歸器模型對異常值不那麼敏感,就須要設置一個比較大的alpha值(《Python機器學習經典實例》是這麼說的,但我表示嚴重懷疑,緣由後面會講)。因此alpha值的選取是個技術活。
#################################################################
一樣的,和線性迴歸器模型同樣,咱們也須要對嶺迴歸器模型進行評估,以考察該模型的好壞。一樣的,可使用均方偏差MSE來評估該模型的好壞。
爲了對本模型進行評估,須要有評估所需的測試集,此處我本身用隨機數生成了一些測試集,以下爲測試集生成代碼。
# 嶺迴歸器模型的評估
# 第一步:構建評估數據,即test set
test_x=np.arange(10,20) # 自變量,隨便定義的
shift=np.random.normal(size=test_x.shape)
test_x=test_x+shift # 對test_x進行偏置獲得測試集的X
error=np.random.normal(size=x.shape)
test_y=1.8*test_x+5.9+error # 添加隨機數做爲噪音
plt.scatter(whole_x,whole_y,color='blue',label='train_set')
plt.scatter(test_x,test_y,color='red',label='test_set')
plt.legend()
# 把train set和test set都繪製到一個圖中,能夠看出誤差不大
複製代碼
從上面數據點的分佈來看,除了train set中異常點的位置沒有test set以外,其他點都和test set的分佈是一致的,代表這個test set能夠用於進行測試。
# 第二步:使用test set計算MSE
y_test_predict=ridge_regressor.predict(test_x.reshape(-1,1))
# 第三步:使用評價指標來評估模型的好壞
import sklearn.metrics as metrics
test_y=test_y.reshape(-1,1)
print('平均絕對偏差:{}'.format(
round(metrics.mean_absolute_error(y_test_predict,test_y),2)))
print('均方偏差MSE:{}'.format(
round(metrics.mean_squared_error(y_test_predict,test_y),2)))
print('中位數絕對偏差:{}'.format(
round(metrics.median_absolute_error(y_test_predict,test_y),2)))
print('解釋方差分:{}'.format(
round(metrics.explained_variance_score(y_test_predict,test_y),2)))
print('R方得分:{}'.format(
round(metrics.r2_score(y_test_predict,test_y),2)))
複製代碼
-------------------------------------輸---------出--------------------------------
平均絕對偏差:2.29 均方偏差MSE:8.32 中位數絕對偏差:2.0 解釋方差分:0.53 R方得分:0.33
--------------------------------------------完-------------------------------------
########################小**********結###############################
1,在考察train set和test set時須要考慮兩個數據集中數據點的分佈,儘可能使得二者在空間上的分佈一致,這樣才能準確地測試模型。
2,本次模型在test set上的效果並不太理想,雖然獲得的MSE比較小,可是R方得分,解釋方差分都偏低,看來還有改進的餘地。
#################################################################
從上面獲得的嶺迴歸器模型在測試集上的表現能夠看出,本模型效果並不太好,能夠改進的地方至少有兩個,一個是對train set中數據點進行刪減,好比發現了很明顯偏離的異常點,能夠直接將這些異常點刪除,可是這就涉及到異常點的鑑定方法,把哪些點標註爲能夠刪除的異常點,偏離中心位置多少距離就被認定爲異常點,等等。另一個方法是優化嶺迴歸器的alpha值,下面是我嘗試優化alpha的結果圖。
# 對嶺迴歸器模型進行優化,主要優化alpha的取值
alpha_candidates=[-20,-10,-5.0,-2.0,2.0,5.0,10,20,50]
from sklearn import linear_model
for alpha in alpha_candidates:
ridge_regressor=linear_model.Ridge(alpha=alpha,fit_intercept=True,max_iter=10000)
# 構建嶺迴歸器對象,使用不一樣的alpha值
ridge_regressor.fit(whole_x,whole_y) # 使用嶺迴歸器進行訓練
# 使用訓練完成的嶺迴歸器預測數值
y_train_predict=ridge_regressor.predict(whole_x)
plt.plot(whole_x,y_train_predict,label='alpha='+str(alpha))
plt.legend()
plt.scatter(whole_x,whole_y)
複製代碼
從上圖中能夠看出,隨着alpha的取值由0到50慢慢變化,擬合直線會進行順時針旋轉,或者是朝向異常點的方向旋轉,貌似是由於alpha越大,異常點對直線越「吸引」,故而擬合直線收到異常點的影響也愈來愈大。而alpha由0變到負值,且愈來愈小時,異常點對擬合直線的影響也愈來愈小。(不知道這麼總結對不對)。雖然linear_model. Ridge的函數說明文檔要求alpha取值是positive float,可是此處負值貌似也沒有問題,並且貌似alpha爲負值時擬合的更好一些。
下面打印出各類不一樣alpha值時的各類偏差:
# 對嶺迴歸器模型進行優化,使用不一樣alpha值優化後獲得的模型計算測試集
alpha_candidates=[-20,-10,-5.0,-2.0,2.0,5.0,10,20,50]
from sklearn import linear_model
for alpha in alpha_candidates:
ridge_regressor=linear_model.Ridge(alpha=alpha,fit_intercept=True,max_iter=10000)
# 構建嶺迴歸器對象,使用不一樣的alpha值
ridge_regressor.fit(whole_x,whole_y) # 使用嶺迴歸器進行訓練
y_test_predict=ridge_regressor.predict(test_x.reshape(-1,1))
print('------------alpha='+str(alpha)+'---------------------->>>')
print('均方偏差MSE:{}'.format(
round(metrics.mean_squared_error(y_test_predict,test_y),2)))
print('中位數絕對偏差:{}'.format(
round(metrics.median_absolute_error(y_test_predict,test_y),2)))
print('解釋方差分:{}'.format(
round(metrics.explained_variance_score(y_test_predict,test_y),2)))
print('R方得分:{}'.format(
round(metrics.r2_score(y_test_predict,test_y),2)))
複製代碼
-------------------------------------輸---------出--------------------------------
------------alpha=-20----------------------
均方偏差MSE:4.93
中位數絕對偏差:1.1
解釋方差分:0.87
R方得分:0.75
------------alpha=-10----------------------
均方偏差MSE:6.61
中位數絕對偏差:1.62
解釋方差分:0.73
R方得分:0.57
------------alpha=-5.0----------------------
均方偏差MSE:7.47
中位數絕對偏差:1.84
解釋方差分:0.64
R方得分:0.46
------------alpha=-2.0----------------------
均方偏差MSE:7.98
中位數絕對偏差:1.96
解釋方差分:0.57
R方得分:0.38
------------alpha=2.0----------------------
均方偏差MSE:8.66
中位數絕對偏差:2.03
解釋方差分:0.48
R方得分:0.27
------------alpha=5.0----------------------
均方偏差MSE:9.15
中位數絕對偏差:2.06
解釋方差分:0.41
R方得分:0.18
------------alpha=10----------------------
均方偏差MSE:9.95
中位數絕對偏差:2.12
解釋方差分:0.27
R方得分:0.02
------------alpha=20----------------------
均方偏差MSE:11.47
中位數絕對偏差:2.33
解釋方差分:-0.05
R方得分:-0.36
------------alpha=50----------------------
均方偏差MSE:15.31
中位數絕對偏差:2.78
解釋方差分:-1.36
R方得分:-1.87
########################小**********結###############################
1,經過修改alpha值,能夠修改模型在test set上的表現,因爲test set不包含異常點,因此要求alpha取的越小越好,擬合的直線越偏離異常點。
2,alpha取值越大,嶺迴歸獲得的擬合直線越「偏向」異常點,此時異常點對直線的影響越大;alpha越小,擬合直線越「偏離」異常點,此時異常點對直線的影響越小,咱們所指望的是異常點對直線影響越小越好,因此貌似alpha應該往越小的方向取值。
#################################################################
注:本部分代碼已經所有上傳到(個人github)上,歡迎下載。
參考資料:
1, Python機器學習經典實例,Prateek Joshi著,陶俊傑,陳小莉譯