多項式迴歸與模型泛化(中)

本人和機器學習已經久違了,暑假難得有時間,來學一學並和大家分享,希望小夥伴們不吝賜教!

一. 過擬合與欠擬合

我們實際希望的,是在新樣本上能表現得很好的學習器。爲了達到這個目的,應該從訓練樣本中儘可能選出適用於所有潛在樣本的“普遍規律”,這樣才能在遇到新樣本時做出正確的判別.然而,當學習器把訓練樣本學得“太好”了的時候,很可能巳經把訓練樣本自身的一些特點當作了所有潛在樣本都會具有的一般性質,這樣就會導致泛化性能下降,這種現象在機器學習中稱爲“過擬合” 。 與"過擬合"相對的是“欠擬合” ,這是指對訓練樣本的一般性質尚未擬合學習好。

廢話不多說,上才藝:

在之前我們用多項式迴歸來代替線性迴歸的時候,傳入一個參數 degreedegree 用來表示我們需要擬合多項式的最高次冪,像這樣:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import PolynomialFeatures
x = np.random.uniform(-3,3,size = 100)
X = x.reshape(-1,1)
y = 0.5* x **2+ x + 2 + np.random.normal(0,1,100)

def PolynomialRegression(degree): 
        return  Pipeline([
                           ("poly",PolynomialFeatures(degree=3)),
                            ("std_scaler",StandardScaler()),
                            ("iin_reg",LinearRegression())
       					 ])
poly_reg.fit(X,y)
y_predict = poly_reg.predict(X)        
plt.scatter(x,y)
plt.plot(np.sort(x),y_predict[np.argsort(x)],color = 'r')
plt.show()

在這裏插入圖片描述
這裏我們還是從頭實現一下源碼!注意,這時我們傳入的degree = 2,此時我們希望能夠更好的擬合這些離散點,提高degree 的值看看:

poly10_reg = PolynomialRegression(degree=10)
poly10_reg.fit(X,y)
y10_predict = poly10_reg.predict(X)
plt.scatter(x,y)
plt.plot(np.sort(x),y10_predict[np.argsort(x)],color = 'r')
plt.show()

在這裏插入圖片描述
顯然,這似乎更能貼切的擬合這些離散的點!是不是我們增加degree 的值就可以能夠更好地擬合模型呢? 索性加到100!

在這裏要注意,如果你直接將degree的值改到100的話,得到的圖並不是我們需要的擬合曲線,而是根據這些離散點繪製的:
在這裏插入圖片描述
我們還學要進一步處理才能得到真的degree爲100的那個擬合曲線!

X_plot = np.linspace(-3, 3, 100).reshape(100, 1)
y_plot = poly100_reg.predict(X_plot)
plt.scatter(x,y)
plt.plot(X_plot[:,0],y_plot,color = 'r')
plt.axis([-3,3,-1,10])
plt.show()

在這裏插入圖片描述
浮誇歸浮誇,結果還是它!如果您不介意,可以繼續提高degree 的值,最後有可能所有的離散點都在一條曲線上,同時,均方誤差MSE可能無限 的趨近 0,但是這並沒有啥子用!因爲它已經完全不能代表和預測我們樣本點的走勢了,只是單純的爲我們降低MSE!這也就是我們耳熟能詳的 “過擬合”,那麼欠擬合就更簡單了,也就是degree 的值太小,擬合不了這些點的趨勢!

這話又說回來了,既然這個degree 調高了不行,調少了也不行,那麼我們如何能夠找到適合模型的degree 呢!這就是玄學了,不過目前我們所需要知道的,就是將原始數據集分成trian 和 test 數據集!根據初始化degree先擬合一下,將test帶入其中並計算準確率,在回過頭來調degree !所以,數據集分開的重要意義就是調參數提升擬合效果!

二. train_test_spilt 的意義

這裏我們重新建立一個文件,以防混淆!

import numpy as np  #導包
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression 
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import PolynomialFeatures

np.random.seed(666) 
x = np.random.uniform(-3,3,size = 100)
X = x.reshape(-1,1)
y = 0.5* x **2 + x + 2 + np.random.normal(0,1,100)

完成的導包和建立隨機數據之後,我們將其分開!

X_train,X_test,y_train,y_test = train_test_split(X,y,random_state = 666)

我們先來測試一下 對於線性迴歸的模型擬合效果怎麼樣!

lin_reg = LinearRegression() #先試用線性迴歸 MSE看一下誤差!
lin_reg.fit(X_train,y_train) #先用X_train數據訓練模型 再用X_test 預測,將預測值與 真正的y_predict求MSE
y_predict = lin_reg.predict(X_test) 
mean_squared_error (y_test,y_predict)

得到的值爲:2.2199965269396573

注意後面預測的時候我用的是X_test ,求MSE是用的是 真實的y_test 與以 X_train,y_trian 建立模型預測得到的y_predict 進行對比計算,千萬不要弄混!

同樣的方式,我們採用多項式迴歸來看看會好多少!

def PolynomialRegression (degree):
    return Pipeline([
        ("poly",PolynomialFeatures(degree=degree)),
       ("std_scaler",StandardScaler()),
        ("iin_reg",LinearRegression()) 
    ])
    
poly_reg = PolynomialRegression(degree = 2)
poly_reg.fit(X_train,y_train)
y2_predict = poly_reg.predict(X_test)
mean_squared_error(y_test,y2_predict) #此處的泛化能力更強!

在這裏插入圖片描述
顯然,這裏模型的泛化能力更強!如果我們提高degree的值會怎麼樣呢!

poly10_reg = PolynomialRegression(degree = 10)
poly10_reg.fit(X_train,y_train)
y10_predict = poly10_reg.predict(X_test)
mean_squared_error(y_test,y10_predict)

在這裏插入圖片描述
這裏的MSE 已經變大了,說明模型的擬合效果開始變得不好了,因爲過擬合了!

綜合上面的解釋,我們可以畫一張圖直觀的展示這些關係!
在這裏插入圖片描述
算法工程師的一個重要工作就是調參,已達到我們上圖中test曲線的最高值!

三. 學習曲線

定義: 隨着訓練樣本的逐漸增多,算法訓練出的模型的表現能力!

這裏和前面說的 有點不一樣了,最大區別在於它是需要我們逐漸向其中增加樣本數量,逐漸擬合,前面的模型擬合都是一蹴而就的,容易出差錯!

直接上算法源碼,這裏還是用起上面我們剛使用過的隨機數據!

X_train,X_test,y_train,y_test = train_test_split(X,y,random_state = 6)
def plot_learning_curve(algo,X_train,X_test,y_train,y_test):
    train_score = []
    test_scroe = []
    
    for i in range(1,len(X_train)+1):
        algo.fit(X_train[:i],y_train[:i])

        y_train_predict = algo.predict(X_train[:i])
        train_score.append(mean_squared_error(y_train[:i],y_train_predict))

        y_test_predict = algo.predict(X_test)
        test_scroe.append(mean_squared_error(y_test,y_test_predict))
        
    plt.plot([i for i in range(1,len(X_train)+1)],np.sqrt(train_score),label="train")
    plt.plot([i for i in range(1,len(X_train)+1)],np.sqrt(test_scroe),label="test")
    plt.legend()
    plt.axis([0,len(X_train)+1,0,4])
    plt.show()

我們選好擬合模型之後,每傳入一次數據,就進行一次擬合,直到將我們之前分好的數據集全部代入計算完成,大概的思路就是這樣,代碼也非常的簡單!就不多解釋了!

我們使用這個算法:

plot_learning_curve(LinearRegression(),X_train,X_test,y_train,y_test) #線性迴歸的學習率

在這裏插入圖片描述
算法先用train 數據集去套擬合模型,所以剛開始樣本數據非常少的時候,test數據預測的誤差會非常大,這和上圖中橘黃色的曲線是吻合的,可以不用管它,隨着數據逐漸加入,最後二者的MSE 會 平和的匯聚在一起!

如果你過擬合了,degree太高了 ,就會出現這樣:

ploy20_reg = PolynomialRegression(degree=20)
plot_learning_curve(ploy20_reg,X_train,X_test,y_train,y_test)#高階多項式數據擬合學習曲線

在這裏插入圖片描述
大家都可以看到這樣的話,就不太友好,間距太大,test數據集的誤差太大了!

所以,綜上可以看出 學習曲線也是幫助我們 調參,防止過擬合或者是欠擬合的一個較爲穩定的好方法!

本期就到這裏了,祝大家生活愉快!

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