05 機器學習算法之多項式迴歸

機器學習算法之多項式迴歸

目錄:

  • 1.多項式迴歸簡介
  • 2.編程實驗多項式迴歸
  • 3.過擬合和欠擬合
  • 4.學習曲線
  • 5.驗證數據集與交叉驗證
  • 6.偏差方差均衡
  • 7.模型正則化

一、多項式迴歸簡介

考慮下面的數據,雖然我們可以使用線性迴歸來擬合這些數據,但是這些數據更像是一條二次曲線,相應的方程是y=ax2+bx+c,這個式子雖然可以理解爲二次方程,但是我們呢可以從另外一個角度來理解這個式子:

如果將x2理解爲一個特徵,將x理解爲另外一個特徵,換句話說,本來我們的樣本只有一個特徵x,現在我們把他看成有兩個特徵的一個數據集。多了一個特徵x2,那麼從這個角度來看,這個式子依舊是一個線性迴歸的式子,但是從x的角度來看,他就是一個二次的方程

多項式迴歸:相當於爲樣本添加了一些特徵,這些特徵是原來樣本的多項式項,增加了這些特徵之後,我們可以使用線性迴歸的思路更好的擬合我們的數據。

二、編程實驗多項式迴歸

1.模擬多項式迴歸的數據集

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

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,size=100)

plt.scatter(x,y)
<matplotlib.collections.PathCollection at 0x1665e9db6a0>

在這裏插入圖片描述

2.使用線性迴歸擬合數據

from sklearn.linear_model import LinearRegression

lin_reg = LinearRegression()
lin_reg.fit(X,y)
y_predict = lin_reg.predict(X)

plt.scatter(x,y)
plt.plot(X,y_predict,color="r")
[<matplotlib.lines.Line2D at 0x1665eefd940>]

在這裏插入圖片描述

很明顯,用一條直線來擬合有弧度的曲線,效果是不好的。

3.解決方案,添加一個特徵

原來的數據都在X中,現在對X中每一個數據都進行平方

再將得到的數據集與原數據集進行拼接

再用新的數據集進行線性迴歸

(X**2).shape
(100, 1)
X2 = np.hstack([X,X**2])
lin_reg2 = LinearRegression()
lin_reg2.fit(X2,y)
y_predict2 = lin_reg2.predict(X2)

plt.scatter(x,y)
plt.plot(np.sort(x),y_predict2[np.argsort(x)],color="r")
[<matplotlib.lines.Line2D at 0x166615f3710>]

在這裏插入圖片描述

總之:

多項式迴歸在機器學習算法上並沒有新的地方,完全是使用線性迴歸的思路

它的關鍵在於爲原來的樣本,添加新的特徵,而我們得到新的特徵的方式在在原有特徵的多項式的組合。

採用這樣的方式,我們就可以解決一些非線性的問題。

與此同時需要注意,PCA是對我們的數據機芯降維處理,而多項式迴歸是讓數據升維,在升維之後使得算法可以更好的擬合高緯度的數據

4.sklearn中的多項式迴歸

# 數據進行處理
from sklearn.preprocessing import PolynomialFeatures

poly = PolynomialFeatures()
poly.fit(X)
X3 = poly.transform(X)
X3[:5]
array([[ 1.        ,  2.4708992 ,  6.10534284],
       [ 1.        , -1.28689158,  1.65608995],
       [ 1.        ,  0.70399937,  0.49561511],
       [ 1.        , -0.91605936,  0.83916474],
       [ 1.        ,  1.36063097,  1.85131664]])
# 調用LinearRegression對X2進行預測
lin_reg3 = LinearRegression()
lin_reg3.fit(X3,y)
y_predict3 = lin_reg3.predict(X3)

plt.scatter(x,y)
plt.plot(np.sort(x),y_predict3[np.argsort(x)],color="r")
[<matplotlib.lines.Line2D at 0x166616262b0>]

在這裏插入圖片描述

5.使用Pipline來實現多項式迴歸的過程

pipline的英文名字是管道,那麼如何使用管道呢,先考慮我們的多項式迴歸的過程

  • 1.使用PolynomialFeatures生成多項式特徵的數據集
  • 2.如果生成數據冪特別的大,那麼特徵之間的差距就會很大,導致我們的搜索非常慢,這時候就需要數據歸一化
  • 3.進行線性迴歸

pipline的作用就是把上面的三個步驟合併,使得我們不用一直重複這三步

# 準備數據
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,size=100)
# pipline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# 傳入每一步的對象名和類的實例化
poly_reg = Pipeline([
    ("poly",PolynomialFeatures(degree=2)),
    ("std_scaler",StandardScaler()),
    ("lin_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")
[<matplotlib.lines.Line2D at 0x16661626208>]

在這裏插入圖片描述

三、過擬合和欠擬合

1.什麼是過擬合和欠擬合

# 數據準備
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

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,size=100)

a.線性迴歸

lin_reg = LinearRegression()
lin_reg.fit(X,y)
y_predict = lin_reg.predict(X)

plt.scatter(x,y)
plt.plot(X,y_predict,color='r')
[<matplotlib.lines.Line2D at 0x16661682400>]

在這裏插入圖片描述

from sklearn.metrics import mean_squared_error

y_predict = lin_reg.predict(X)
mean_squared_error(y,y_predict)
3.3341226155406303

2.使用多項式迴歸

# 使用Pipeline構建多項式迴歸
def PolynomialRegression(degree):
    poly_reg = Pipeline([
        ('poly',PolynomialFeatures(degree=degree)),
        ('std_scaler',StandardScaler()),
        ('lin_reg',LinearRegression())
    ])
    return poly_reg

poly_reg2 = PolynomialRegression(2)
poly_reg2.fit(X,y)
y2_predict = poly_reg2.predict(X)
# 顯然使用多項式迴歸得到的結果是更好的
mean_squared_error(y,y2_predict)
1.111897309325084
plt.scatter(x,y)
plt.plot(np.sort(x),y2_predict[np.argsort(x)],color='r')
[<matplotlib.lines.Line2D at 0x1666175e470>]

在這裏插入圖片描述

3.使用更高的維度進行多項式迴歸

a.使用10個維度

# 使用10個維度
poly_reg10 = PolynomialRegression(10)
poly_reg10.fit(X,y)
y10_predict = poly_reg10.predict(X)
mean_squared_error(y,y10_predict)
0.9427318831233271
plt.scatter(x,y)
plt.plot(np.sort(x),y10_predict[np.argsort(x)],color='r')
[<matplotlib.lines.Line2D at 0x166617b25c0>]

在這裏插入圖片描述

b.使用100個維度

poly_reg100 = PolynomialRegression(100)
poly_reg100.fit(X,y)
y100_predict = poly_reg100.predict(X)
# 顯然使用多項式迴歸得到的結果是更好的
mean_squared_error(y,y100_predict)
0.5566399955159339
plt.scatter(x,y)
plt.plot(np.sort(x),y100_predict[np.argsort(x)],color='r')
[<matplotlib.lines.Line2D at 0x16661827208>]

在這裏插入圖片描述

X_plot = np.linspace(-3,3,100).reshape(100,1)
y_plot = poly_reg100.predict(X_plot)

plt.scatter(x,y)
plt.plot(X_plot,y_plot,color='r')
plt.axis([-3 , 3 , -1,10 ])
[-3, 3, -1, 10]

在這裏插入圖片描述

總結

degree從2到10到100的過程中,雖然均方誤差是越來越小的,從均方誤差的角度來看是更加小的
但是他真的能更好的預測我們數據的走勢嗎,例如我們選擇2.5到3的一個x,使用上圖預測出來的y的大小(0或者-1之間)顯然不符合我們的數據

  • 換句話說,我們使用了一個非常高的數據,雖然使得我們的樣本點獲得了更小的誤差,但是這條曲線完全不是我們想要的樣子,它爲了擬合我們所有的樣本點,變得太過於複雜了,這種情況就是過擬合
  • 相反,在最開始,我們直接使用一根直線來擬合我們的數據,也沒有很好的擬合我們的樣本特徵,當然它犯的錯誤不是太過於複雜,而是太過簡單,這種情況就是欠擬合

對於上述這樣的一個圖,會有兩條曲線:

  • 一個是對於訓練數據集來說的,模型越複雜,模型準確率越高,因爲模型越複雜,對訓練數據集的擬合就越好,相應的模型準確率就越高
  • 對於測試數據集來說,在模型很簡單的時候,模型的準確率也比較低,隨着模型逐漸變複雜,對測試數據集的準確率在逐漸的提升,提升到一定程度後,如果模型繼續變複雜,那麼我們的模型準確率將會進行下降(欠擬合->正合適->過擬合)

欠擬合和過擬合的標準定義

  • 欠擬合:算法所訓練的模型不能完整表述數據關係
  • 過擬合:算法所訓練的模型過多的表達了數據間的噪音關係

四、學習曲線

1.什麼是學習曲線

隨着訓練樣本的逐漸增大,算法訓練出的模型的表現能力

import numpy as np
import matplotlib.pyplot as plt

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,size=100)

plt.scatter(x,y)
<matplotlib.collections.PathCollection at 0x166618de2e8>

在這裏插入圖片描述

2.實際編程實現學習曲線

from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=10)

print(X_train.shape,type(X_train))
print(X_test.shape,type(X_test))
print(y_train.shape,type(y_train))
print(y_test.shape,type(y_test))
(75, 1) <class 'numpy.ndarray'>
(25, 1) <class 'numpy.ndarray'>
(75,) <class 'numpy.ndarray'>
(25,) <class 'numpy.ndarray'>

a.觀察線性迴歸的學習曲線

觀察線性迴歸的模型,隨着訓練數據集增加,性能的變化

from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

def plot_learning_curve(algo,X_train,X_test,y_train,y_test):
    train_score = []
    test_score = []

    # 計算學習曲線數據
    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_score.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_score),label = 'test')
    plt.axis([0,len(X_train)+1,0,4])
    plt.legend()

    
plot_learning_curve(LinearRegression(),X_train,X_test,y_train,y_test)

在這裏插入圖片描述

從趨勢上看:

  • 在訓練數據集上,誤差是逐漸升高的。這是因爲我們的訓練數據越來越多,我們的數據點越難得到全部的累積,不過整體而言,在剛開始的時候誤差變化的比較快,後來就幾乎不變了
  • 在測試數據集上,在使用非常少的樣本進行訓練的時候,剛開始我們的測試誤差非常的大,當訓練樣本大到一定程度以後,我們的測試誤差就會逐漸減小,減小到一定程度後,也不會小太多,達到一種相對穩定的情況
  • 在最終,測試誤差和訓練誤差趨於相等,不過測試誤差還是高於訓練誤差一些,這是因爲,訓練數據在數據非常多的情況下,可以將數據擬合的比較好,誤差小一些,但是泛化到測試數據集的時候,還是有可能多一些誤差

b.觀察多項式迴歸的學習曲線

from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline

# 使用Pipline構建多項式迴歸模型
def PolynomialRegression(degree):
    return Pipeline([
    ("poly",PolynomialFeatures(degree=degree)),
    ("std_scaler",StandardScaler()),
    ("lin_reg",LinearRegression())
    ])

# 使用二階多項式迴歸
poly2_reg = PolynomialRegression(2)
plot_learning_curve(poly2_reg,X_train,X_test,y_train,y_test)

在這裏插入圖片描述

首先整體從趨勢上,和線性迴歸的學習曲線是類似的

仔細觀察,和線性迴歸曲線的不同在於,線性迴歸的學習曲線1.5,1.8左右;2階多項式迴歸穩定在了1.0,0.9左右,2階多項式穩定的誤差比較低,說明使用二階線性迴歸的性能是比較好的

# 使用20階多項式迴歸
poly20_reg = PolynomialRegression(20)
plot_learning_curve(poly20_reg,X_train,X_test,y_train,y_test)

在這裏插入圖片描述

在使用20階多項式迴歸訓練模型的時候可以發現,在數據量偏多的時候,我們的訓練數據集擬合的是比較好的,但是測試數據集的誤差相對來說增大了很多,離訓練數據集比較遠,通常這就是過擬合的結果,他的泛化能力是不夠的

五、驗證數據集與交叉驗證

使用分割訓練數據集合測試數據集來判斷我們的機器學習性能的好壞,雖然是一個非常好的方案,但是會產生一個問題:針對特定測試數據集過擬合

我們每次使用測試數據來分析性能的好壞,一旦發現結果不好,我們就換一個參數(可能是degree也可能是其他超參數)重新進行訓練。這種情況下,我們的模型在一定程度上圍繞着測試數據集打轉。也就是說我們在尋找一組參數,使得這組參數訓練出來的模型在測試結果集上表現的最好。但是由於這組測試數據集是已知的,我們相當於在針對這組測試數據集進行調參,那麼他也有可能產生過擬合的情況,也就是我們得到的模型針對測試數據集過擬合了

那麼怎麼解決這個問題呢?

解決的方式就是:我們需要將我們的數據集分爲三部分,這三部分分別是訓練數據集,驗證數據集,測試數據集。

我們使用訓練數據集訓練好模型之後,將驗證數據集送給這個模型,看看這個訓練數據集訓練的效果是怎麼樣的,如果效果不好,我們重新換參數,重新訓練模型,直到我們的模型針對驗證數據集已經達到最優。

這樣我們的模型達到最優之後,再將測試數據集送給模型,這樣才能作爲衡量模型最終的性能。

換句話說我們的測試數據集是不參與模型的創建的,而其他兩個數據集都參與了訓練。但是我們的測試數據集對於模型是完全不可知的,相當於我們在模型這個模型完全不知道的數據

這種方法還會有一個問題。由於我們的模型可能會針對驗證數據集過擬合,而我們只有一份驗證數據集,一旦我們的數據集裏有比較極端的情況,那麼模型的性能就會下降很多,那麼爲了解決這個問題,就有了交叉驗證。

1.交叉驗證

交叉驗證相對來說是比較正規的、比較標準的在我們調整我們的模型參數的時候看我們的性能的方式

交叉驗證:在訓練模型的時候,通常把數據分成k份,例如分成3份(ABC)(分成k分,k屬於超參數),這三份分別作爲驗證數據集和訓練數據集。這樣組合後可以分別產生三個模型,這三個模型,每個模型在測試數據集上都會產生一個性能的指標,這三個指標的平均值作爲當前這個算法訓練處的模型衡量的標準是怎樣的。

由於我們有一個求平均的過程,所以不會由於一份驗證數據集中有比較極端的數據而導致模型有過大的偏差,這比我們只分成訓練、驗證、測試數據集要更加準確

2.編程實現

import numpy as np
from sklearn import datasets
digits = datasets.load_digits()
X = digits.data
y = digits.target
from sklearn.model_selection import train_test_split

X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.4,random_state =666)
from sklearn.neighbors import KNeighborsClassifier

best_score,best_k,best_p = 0,0,0
# k爲k近鄰中的尋找k個最近元素
for k in range(2,10):
    # p爲明科夫斯基距離的p
    for p in range(1,5):
        knn_clf = KNeighborsClassifier(weights='distance',n_neighbors=k,p=p)
        knn_clf.fit(X_train,y_train)
        score = knn_clf.score(X_test,y_test)
        if score > best_score:
            best_score,best_k,best_p = score,k,p
print("Best_score = ",best_score)
print("Best_k = ",best_k)
print("Best_p = ",best_p)
Best_score =  0.9860917941585535
Best_k =  3
Best_p =  4

3.交叉驗證

# 使用sklearn提供的交叉驗證
from sklearn.model_selection import cross_val_score
# 使用交叉驗證的方式來進行調參的過程
best_score,best_k,best_p = 0,0,0
# k爲k近鄰中的尋找k個最近元素
for k in range(2,10):
    # p爲明科夫斯基距離的p
    for p in range(1,5):
        knn_clf = KNeighborsClassifier(weights='distance',n_neighbors=k,p=p)
        scores = cross_val_score(knn_clf,X_train,y_train)
        score = np.mean(scores)
        if score > best_score:
            best_score,best_k,best_p = score,k,p
print("Best_score = ",best_score)
print("Best_k = ",best_k)
print("Best_p = ",best_p)
Best_score =  0.9823599874006478
Best_k =  2
Best_p =  2

通過觀察兩組調參過程的結果可以發現

  • 1.兩組調參得出的參數結果是不同的,通常這時候我們更願意詳細使用交叉驗證的方式得出的結果。
    因爲使用train_test_split很有可能只是過擬合了測試數據集得出的結果
  • 2.使用交叉驗證得出的最好分數0.982是小於使用分割訓練測試數據集得出的0.986,因爲在交叉驗證的
    過程中,通常不會過擬合某一組的測試數據,所以平均來講這個分數會稍微低一些

但是使用交叉驗證得到的最好參數Best_score並不是真正的最好的結果,我們使用這種方式只是爲了拿到
一組超參數而已,拿到這組超參數後我們就可以訓練處我們的最佳模型

knn_clf = KNeighborsClassifier(weights='distance',n_neighbors=2,p=2)
# 用我們找到的k和p。來對X_train,y_train整體fit一下,來看他對X_test,y_test的測試結果
knn_clf.fit(X_train,y_train)
# 注意這個X_test,y_test在交叉驗證過程中是完全沒有用過的,也就是說我們這樣得出的結果是可信的
knn_clf.score(X_test,y_test)
0.980528511821975

4.網格搜索

我們上面的操作,實際上在網格搜索的過程中已經進行了,只不過這個過程是sklean的網格搜索自帶的一個過程

# GridSearchCV裏的cv實際上就是交叉驗證的方式
from sklearn.model_selection import GridSearchCV

param_grid = [
{
"weights":['distance'],
"n_neighbors":[i for i in range(2,10)],
"p":[i for i in range(1,6)]
}
]
knn_clf = KNeighborsClassifier()
# cv默認爲3,可以修改改參數,修改修改不同分數的數據集
grid_search = GridSearchCV(knn_clf,param_grid,verbose=1,cv=3)
grid_search.fit(X_train,y_train)
Fitting 3 folds for each of 40 candidates, totalling 120 fits


[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 120 out of 120 | elapsed:  1.5min finished





GridSearchCV(cv=3, error_score='raise-deprecating',
       estimator=KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=None, n_neighbors=5, p=2,
           weights='uniform'),
       fit_params=None, iid='warn', n_jobs=None,
       param_grid=[{'weights': ['distance'], 'n_neighbors': [2, 3, 4, 5, 6, 7, 8, 9], 'p': [1, 2, 3, 4, 5]}],
       pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
       scoring=None, verbose=1)
grid_search.best_score_
# 和我們上面得到的best_score 是吻合的
0.9823747680890538
grid_search.best_params_
{'n_neighbors': 2, 'p': 2, 'weights': 'distance'}
best_knn_clf = grid_search.best_estimator_
best_knn_clf.fit(X_train,y_train)
best_knn_clf.score(X_test,y_test)
0.980528511821975

5.總結

雖然整體速度慢了,但是這個結果卻是可信賴的
極端情況下,K-folds cross validation可以叫做留一法

六、偏差方差均衡

模型誤差=偏差(Bias)均差(Variance)+不可避免的誤差

1.偏差

2.方差

模型沒有完全的學到數據的中心,而學習到了噪音。

機器學習的主要調整來源於方差(這是站在算法的角度上,而不是問題的角度上,比如對金融市場的理解,很多人嘗試用歷史的數據預測未來的金融走勢,這樣的嘗試通常都不太理想。很有可能因爲歷史的金融趨勢不能很好的反應未來的走向,這種預測方法本身帶來的非常大的偏差)換句話說,我們很容易讓模型變的很複雜,從而降低模型的偏差,但是由於這樣的模型的方差非常的大,最終也沒有很好的性能。

3.解決高方差的通常手段

  • 1.降低模型複雜度
  • 2.減少數據維度;降噪;
  • 3.增加樣本數
  • 4.使用驗證集
  • 5.模型正則化

七、模型正則化

1.模型正則化

下面是我們之前使用多項式迴歸過擬合一個樣本的例子,可以看到這條模型曲線非常的彎曲,而且非常的陡峭,可以想象這條曲線的一些θ係數會非常的大。

模型正則化需要做的事情就是限制這些係數的大小。

2.模型正則化基本原理

3.嶺迴歸Ridge Regression

編程實現嶺迴歸

import numpy as np
import matplotlib.pyplot as plt

# 模型樣本
np.random.seed(42)
x = np.random.uniform(-3.0,3.0,size=100)
X = x.reshape(-1,1)
y = 0.5 * x + 3 + np.random.normal(0,1,size=100)

# 繪製樣本曲線
plt.scatter(x,y)
<matplotlib.collections.PathCollection at 0x16661d39a90>

在這裏插入圖片描述

from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline

# 定義多項式迴歸函數
def PolynomialRegression(degree):
    return Pipeline([
    ("poly",PolynomialFeatures(degree=degree)),
    ("std_scaler",StandardScaler()),
    ("lin_reg",LinearRegression())
    ])
from sklearn.model_selection import train_test_split

# 分割數據集
np.random.seed(666)
X_train,X_test,y_train,y_test = train_test_split(X,y)
from sklearn.metrics import mean_squared_error

# 多項式迴歸對樣本進行訓練,使用20個維度
poly20_reg = PolynomialRegression(20)
poly20_reg.fit(X_train,y_train)

y20_predict = poly20_reg.predict(X_test)
mean_squared_error(y_test,y20_predict)
167.9401085999025
# 定義繪圖模型
def plot_module(module):
    X_plot = np.linspace(-3,3,100).reshape(100,1)
    y_plot = module.predict(X_plot)

    plt.scatter(x,y)
    plt.plot(X_plot[:,0],y_plot,color='r')
    plt.axis([-3,3,0,6])
# 繪製模型曲線--過擬合(非常的完全,兩段有極端的情況)
plot_module(poly20_reg)

在這裏插入圖片描述

from sklearn.linear_model import Ridge

def RidgeRegression(degree,alpha):
    return Pipeline([
    ("poly",PolynomialFeatures(degree=degree)),
    ("std_scaler",StandardScaler()),
    ("ridge_reg",Ridge(alpha=alpha))
    ])
# 注意alpha後面的參數是所有theta的平方和,而對於多項式迴歸來說,嶺迴歸之前得到的θ都非常大
# 所以爲了限制讓他們比較小,我們前面係數可以取的小一些
ridge1_reg = RidgeRegression(degree=20,alpha=0.00001)
ridge1_reg.fit(X_train,y_train)
ridge1_predict = ridge1_reg.predict(X_test)
mean_squared_error(y_test,ridge1_predict)
1.3874378026530747
# 通過使用嶺迴歸,使得我們的均方誤差小了非常多,曲線也緩和了非常多
plot_module(ridge1_reg)

在這裏插入圖片描述

ridge2_reg = RidgeRegression(degree=20,alpha=1)
ridge2_reg.fit(X_train,y_train)
ridge2_predict = ridge2_reg.predict(X_test)
mean_squared_error(y_test,ridge2_predict)
1.1888759304218461
# 讓ridge2_reg 的alpha值等於1,均差誤差更加的縮小,並且曲線越來越趨近於一根傾斜的直線
plot_module(ridge2_reg)

在這裏插入圖片描述

ridge3_reg = RidgeRegression(degree=20,alpha=100)
ridge3_reg.fit(X_train,y_train)
ridge3_predict = ridge3_reg.predict(X_test)
mean_squared_error(y_test,ridge3_predict)
1.3196456113086197
# 得到的誤差依然是比較小,但是比之前的1.18大了些,說明正則化做的有些過頭了
plot_module(ridge3_reg)

在這裏插入圖片描述

ridge4_reg = RidgeRegression(degree=20,alpha=100000)
ridge4_reg.fit(X_train,y_train)
ridge4_predict = ridge4_reg.predict(X_test)
mean_squared_error(y_test,ridge4_predict)
# 當alpha非常大,我們的模型實際上相當於就是在優化θ的平方和這一項,使得其最小(因爲MSE的部分相對非常小)
# 而使得θ的平方和最小,就是使得每一個θ都趨近於0,這個時候曲線就趨近於一根直線了
plot_module(ridge4_reg)

在這裏插入圖片描述

4.LASSO

編程實現LASSO

import numpy as np
import matplotlib.pyplot as plt

# 模型樣本
np.random.seed(42)
x = np.random.uniform(-3.0,3.0,size=100)
X = x.reshape(-1,1)
y = 0.5 * x + 3 + np.random.normal(0,1,size=100)

# 繪製樣本曲線
plt.scatter(x,y)
<matplotlib.collections.PathCollection at 0x16661cf8dd8>

在這裏插入圖片描述

from sklearn.linear_model import Lasso

def LassoRegression(degree,alpha):
    return Pipeline([
    ("poly",PolynomialFeatures(degree=degree)),
    ("std_scatter",StandardScaler()),
    ("lasso_reg",Lasso(alpha=alpha))
    ])
# 這裏的alpha起始值比嶺迴歸的時候大了很多,是由於現在是絕對值
lasso1_reg = LassoRegression(degree=20,alpha=0.01)
lasso1_reg.fit(X_train,y_train)
lasso1_predict = lasso1_reg.predict(X_test)
mean_squared_error(lasso1_predict,y_test)
1.149608084325997
plot_module(lasso1_reg)

在這裏插入圖片描述

# 增大alpha繼續試驗
lasso2_reg = LassoRegression(degree=20,alpha=0.1)
lasso2_reg.fit(X_train,y_train)
lasso2_predict = lasso2_reg.predict(X_test)
mean_squared_error(lasso2_predict,y_test)
1.1213911351818648
# 非常接近一根直線
plot_module(lasso2_reg)

在這裏插入圖片描述

# 增大alpha繼續試驗
lasso3_reg = LassoRegression(degree=20,alpha=1)
lasso3_reg.fit(X_train,y_train)
lasso3_predict = lasso3_reg.predict(X_test)
mean_squared_error(lasso3_predict,y_test)
1.8408939659515595
# alpha=1的時候正則化已經過頭了
plot_module(lasso3_reg)

在這裏插入圖片描述

5.總結

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