机器学习----多项式回归
多項式回歸簡介
考慮下面的數據,雖然我們可以使用線性回歸來擬合這些數據,但是這些數據更像是一條二次曲線,相應的方程是y=ax2+bx+c,這是式子雖然可以理解為二次方程,但是我們呢可以從另外一個角度來理解這個式子:
如果將x2理解為一個特征,將x理解為另外一個特征,換句話說,本來我們的樣本只有一個特征x,現在我們把他看成有兩個特征的一個數據集。多了一個特征x2,那么從這個角度來看,這個式子依舊是一個線性回歸的式子,但是從x的角度來看,他就是一個二次的方程
以上這樣的方式,就是所謂的多項式回歸
相當于我們為樣本多添加了一些特征,這些特征是原來樣本的多項式項,增加了這些特征之后,我們們可以使用線性回歸的思路更好的我們的數據
什么是多項式回歸
import numpy as np import matplotlib.pyplot as plt 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) plt.scatter(x, y) plt.show()線性回歸?
from sklearn.linear_model import LinearRegressionlin_reg = LinearRegression() lin_reg.fit(X, y) y_predict = lin_reg.predict(X) plt.scatter(x, y) plt.plot(x, y_predict, color='r') plt.show()很明顯,我們用一跟直線來擬合一根有弧度的曲線,效果是不好的
解決方案, 添加一個特征
原來所有的數據都在X中,現在對X中每一個數據都進行平方,
再將得到的數據集與原數據集進行拼接,
在用新的數據集進行線性回歸
從上圖可以看出,當我們添加了一個特征(原來特征的平方)之后,再從x的維度來看,就形成了一條曲線,顯然這個曲線對原來數據集的擬合程度是更好的
# 第一個系數是x前面的系數,第二個系數是x平方前面的系數 lin_reg2.coef_ array([ 0.99870163, 0.54939125]) lin_reg2.intercept_ 1.88552367865160013.總結
多線性回歸在機器學習算法上并沒有新的地方,完全是使用線性回歸的思路
他的關鍵在于為原來的樣本,添加新的特征。而我們得到新的特征的方式是原有特征的多項式的組合。
采用這樣的方式,我們就可以解決一些非線性的問題
與此同時需要主要,我們在上一章所講的PCA是對我們的數據進行降維處理,而我們這一章所講的多項式回歸顯然在做一件相反的事情,他讓我們的數據升維,在升維之后使得我們的算法可以更好的擬合高緯度的數據
scikit-learn中的多項式回歸和Pipeline
import numpy as np import matplotlib.pyplot as plt 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) # sklearn中對數據進行預處理的函數都封裝在preprocessing模塊下,包括之前學的歸一化StandardScaler from sklearn.preprocessing import PolynomialFeatures poly = PolynomialFeatures(degree=2) # 表示為數據的特征最多添加2次冪 poly.fit(X) X2 = poly.transform(X) X2.shape (100, 3) X[:5,:] array([[ 0.14960154],[ 0.49319423],[-0.87176575],[-1.33024477],[ 0.47383199]]) # 第一列是sklearn為我們添加的X的零次方的特征 # 第二列和原來的特征一樣是X的一次方的特征 # 第三列是添加的X的二次方的特征 X2[:5,:] array([[ 1. , 0.14960154, 0.02238062],[ 1. , 0.49319423, 0.24324055],[ 1. , -0.87176575, 0.75997552],[ 1. , -1.33024477, 1.76955114],[ 1. , 0.47383199, 0.22451675]]) from sklearn.linear_model import LinearRegressionlin_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') plt.show() lin_reg2.coef_ array([ 0. , 0.9460157 , 0.50420543]) lin_reg2.intercept_ 2.1536054095953823關于PolynomialFeatures
X = np.arange(1, 11).reshape(-1, 2) X array([[ 1, 2],[ 3, 4],[ 5, 6],[ 7, 8],[ 9, 10]]) poly = PolynomialFeatures(degree=2) poly.fit(X) X2 = poly.transform(X) X2.shape (5, 6) X2 array([[ 1., 1., 2., 1., 2., 4.],[ 1., 3., 4., 9., 12., 16.],[ 1., 5., 6., 25., 30., 36.],[ 1., 7., 8., 49., 56., 64.],[ 1., 9., 10., 81., 90., 100.]])將5行2列的矩陣進行多項式轉換后變成了5行6列
第一列是1 對應的是0次冪
第二列和第三列對應的是原來的x矩陣,此時他有兩列一次冪的項
第四列是原來數據的第一列平方的結果
第六列是原來數據的第二列平方的結果
第五列是原來數據的兩列相乘的結果
可以想象如果將degree設置為3,那么將產生一下10個元素
也就是說PolynomialFeatures會窮舉出所有的多項式組合
Pipeline
pipline的英文名字是管道,那么 我們如何使用管道呢,先考慮我們多項式回歸的過程
1.使用PolynomialFeatures生成多項式特征的數據集
2.如果生成數據冪特別的大,那么特征直接的差距就會很大,導致我們的搜索非常慢,這時候可以進行數據歸一化
3.進行線性回歸
pipline 的作用就是把上面的三個步驟合并,使得我們不用一直重復這三步
過擬合和欠擬合
import numpy as np import matplotlib.pyplot as plt np.random.seed(666) x = np.random.uniform(-3.0, 3.0, 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) plt.show()使用線性回歸
from sklearn.linear_model import LinearRegressionlin_reg = LinearRegression() lin_reg.fit(X, y) lin_reg.score(X, y) 0.49537078118650091 y_predict = lin_reg.predict(X) plt.scatter(x, y) plt.plot(np.sort(x), y_predict[np.argsort(x)], color='r') plt.show()使用均方誤差來看擬合的結果,這是因為我們同樣都是對一組數據進行擬合,所以使用不同的方法對數據進行擬合
得到的均方誤差的指標是具有可比性的。
使用多項式回歸
from sklearn.pipeline import Pipeline from sklearn.preprocessing import PolynomialFeatures from sklearn.preprocessing import StandardScalerdef PolynomialRegression(degree):return Pipeline([("poly", PolynomialFeatures(degree=degree)),("std_scaler", StandardScaler()),("lin_reg", LinearRegression())]) poly2_reg = PolynomialRegression(degree=2) poly2_reg.fit(X, y) Pipeline(steps=[('poly', PolynomialFeatures(degree=2, include_bias=True, interaction_only=False)), ('std_scaler', StandardScaler(copy=True, with_mean=True, with_std=True)), ('lin_reg', LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False))]) y2_predict = poly2_reg.predict(X) # 顯然使用多項式回歸得到的結果是更好的 mean_squared_error(y, y2_predict) 1.0987392142417856 plt.scatter(x, y) plt.plot(np.sort(x), y2_predict[np.argsort(x)], color='r') plt.show() poly10_reg = PolynomialRegression(degree=10) poly10_reg.fit(X, y)y10_predict = poly10_reg.predict(X) mean_squared_error(y, y10_predict) 1.0508466763764164 plt.scatter(x, y) plt.plot(np.sort(x), y10_predict[np.argsort(x)], color='r') plt.show() poly100_reg = PolynomialRegression(degree=100) poly100_reg.fit(X, y)y100_predict = poly100_reg.predict(X) mean_squared_error(y, y100_predict) 0.68743577834336944 plt.scatter(x, y) plt.plot(np.sort(x), y100_predict[np.argsort(x)], color='r') plt.show()這條曲線只是原來隨機生成的點(分布不均勻)對應的y的預測值連接起來的曲線,不過有x軸很多地方可能沒有數據點,所以連接的結果和原來的曲線不一樣(不是真實的y曲線)。
下面嘗試真正還原原來的曲線(構造均勻分布的原數據集)
總有一條曲線,他能擬合所有的樣本點,使得均方誤差的值為0
degree從2到10到100的過程中,雖然均方誤差是越來越小的,從均方誤差的角度來看是更加小的
但是他真的能更好的預測我們數據的走勢嗎,例如我們選擇2.5到3的一個x,使用上圖預測出來的y的大小(0或者-1之間)顯然不符合我們的數據
換句話說,我們使用了一個非常高維的數據,雖然使得我們的樣本點獲得了更小的誤差,但是這根曲線完全不是我們想要的樣子
他為了擬合我們所有的樣本點,變的太過復雜了,這種情況就是過擬合【over-fitting】
相反,在最開始,我們直接使用一根直線來擬合我們的數據,也沒有很好的擬合我們的樣本特征,當然他犯的錯誤不是太過復雜了,而是太過簡單了
這種情況,我們成為欠擬合-【under-fitting】
對于現在的數據(基于二次方程構造),我們使用低于2項的擬合結果,就是欠擬合;高于2項的擬合結果,就是過擬合
為什么要使用訓練數據集和測試數據集
模型的泛化能力
使用上節的過擬合結果,我們可以得知,雖然我們訓練出的曲線將原來的樣本點擬合的非常好,總體的誤差非常的小, 但是一旦來了新的樣本點,他就不能很好的預測了,在這種情況下,我們就稱我們得到的這條彎彎曲曲的曲線,他的**泛化能力(由此及彼的能力)**非常弱
image.png
訓練數據集和測試數據集的意義
我們訓練的模型目的是為了使得預測的數據能夠盡肯能的準確,在這種情況下,我們觀察訓練數據集的擬合程度是沒有意義的 我們真正需要的是,我們得到的模型的泛化能力更高,解決這個問題的方法也就是使用訓練數據集,測試數據集的分離
測試數據對于我們的模型是全新的數據,如果使用訓練數據獲得的模型面對測試數據也能獲得很好的結果,那么我們就說我們的模型泛化能力是很強的。 如果我們的模型面對測試數據結果很差的話,那么他的泛化能力就很弱。事實上,這是訓練數據集更大的意義
train test split的意義
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666) lin_reg = LinearRegression() lin_reg.fit(X_train, y_train) y_predict = lin_reg.predict(X_test) mean_squared_error(y_test, y_predict) 2.2199965269396573 poly2_reg = PolynomialRegression(degree=2) poly2_reg.fit(X_train, y_train) y2_predict = poly2_reg.predict(X_test) mean_squared_error(y_test, y2_predict) 0.80356410562978997 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) 0.92129307221507939 poly100_reg = PolynomialRegression(degree=100) poly100_reg.fit(X_train, y_train) y100_predict = poly100_reg.predict(X_test) mean_squared_error(y_test, y100_predict) 14075796419.234262剛剛我們進行的實驗實際上在實驗模型的復雜度,對于多項式模型來說,我們回歸的階數越高,我們的模型會越復雜,在這種情況下對于我們的機器學習算法來說,通常是有下面一張圖的。橫軸是模型復雜度(對于不同的算法來說,代表的是不同的意思,比如對于多項式回歸來說,是階數越高,越復雜;對于KNN來說,是K越小,模型越復雜,k越大,模型最簡單,當k=n的時候,模型就簡化成了看整個樣本里,哪種樣本最多,當k=1來說,對于每一個點,都要找到離他最近的那個點),另一個維度是模型準確率(也就是他能夠多好的預測我們的曲線)
通常對于這樣一個圖,會有兩根曲線:
- 一個是對于訓練數據集來說的,模型越復雜,模型準確率越高,因為模型越復雜,對訓練數據集的擬合就越好,相應的模型準確率就越高
- 對于測試數據集來說,在模型很簡單的時候,模型的準確率也比較低,隨著模型逐漸變復雜,對測試數據集的準確率在逐漸的提升,提升到一定程度后,如果模型繼續變復雜,那么我們的模型準確率將會進行下降(欠擬合->正合適->過擬合)
欠擬合和過擬合的標準定義
欠擬合:算法所訓練的模型不能完整表述數據關系 過擬合:算法所訓練的模型過多的表達了數據間的噪音關系
學習曲線
隨著訓練樣本的逐漸增多,算法訓練出的模型的表現能力
import numpy as np import matplotlib.pyplot as plt np.random.seed(666) x = np.random.uniform(-3.0, 3.0, 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) plt.show()學習曲線
實際編程實現學習曲線
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, random_state=10) X_train.shape (75, 1)2.1觀察線性回歸的學習曲線:觀察線性回歸模型,隨著訓練數據集增加,性能的變化
from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_errortrain_score = [] test_score = [] for i in range(1, 76):lin_reg = LinearRegression()lin_reg.fit(X_train[:i], y_train[:i])y_train_predict = lin_reg.predict(X_train[:i])train_score.append(mean_squared_error(y_train[:i], y_train_predict))y_test_predict = lin_reg.predict(X_test)test_score.append(mean_squared_error(y_test, y_test_predict)) plt.plot([i for i in range(1, 76)], np.sqrt(train_score), label="train") plt.plot([i for i in range(1, 76)], np.sqrt(test_score), label="test") plt.legend() plt.show()從趨勢上看:
在訓練數據集上,誤差是逐漸升高的。這是因為我們的訓練數據越來越多,我們的數據點越難得到全部的累積,不過整體而言,在剛開始的時候誤差變化的比較快,后來就幾乎不變了
在測試數據集上,在使用非常少的樣本進行訓練的時候,剛開始我們的測試誤差非常的大,當訓練樣本大到一定程度以后,我們的測試誤差就會逐漸減小,減小到一定程度后,也不會小太多,達到一種相對穩定的情況
在最終,測試誤差和訓練誤差趨于相等,不過測試誤差還是高于訓練誤差一些,這是因為,訓練數據在數據非常多的情況下,可以將數據擬合的比較好,誤差小一些,但是泛化到測試數據集的時候,還是有可能多一些誤差
首先整體從趨勢上,和線性回歸的學習曲線是類似的
仔細觀察,和線性回歸曲線的不同在于,線性回歸的學習曲線1.5,1.8左右;2階多項式回歸穩定在了1.0,0.9左右,2階多項式穩定的誤差比較低,說明使用二階線性回歸的性能是比較好的
在使用20階多項式回歸訓練模型的時候可以發現,在數據量偏多的時候,我們的訓練數據集擬合的是比較好的,但是測試數據集的誤差相對來說增大了很多,離訓練數據集比較遠,通常這就是過擬合的結果,他的泛化能力是不夠的
總結
對于欠擬合比最佳的情況趨于穩定的那個位置要高一些,說明無論對于訓練數據集還是測試數據集來說,誤差都比較大。這是因為我們本身模型選的就不對,所以即使在訓練數據集上,他的誤差也是大的,所以才會呈現出這樣的一種形態
對于過擬合的情況,在訓練數據集上,他的誤差不大,和最佳的情況是差不多的,甚至在極端情況,如果degree取更高的話,那么訓練數據集的誤差會更低,但是問題在于,測試數據集的誤差相對是比較大的,并且訓練數據集的誤差和測試數據集的誤差相差比較大(表現在圖上相差比較遠),這就說明了此時我們的模型的泛化能力不夠好,他的泛化能力是不夠的
驗證數據集與交叉驗證
使用分割訓練數據集和測試數據集來判斷我們的機器學習性能的好壞,雖然是一個非常好的方案,但是會產生一個問題:針對特定測試數據集過擬合
我們每次使用測試數據來分析性能的好壞。一旦發現結果不好,我們就換一個參數(可能是degree也可能是其他超參數)重新進行訓練。這種情況下,我們的模型在一定程度上圍繞著測試數據集打轉。也就是說我們在尋找一組參數,使得這組參數訓練出來的模型在測試結果集上表現的最好。但是由于這組測試數據集是已知的,我們相當于在針對這組測試數據集進行調參,那么他也有可能產生過擬合的情況,也就是我們得到的模型針對測試數據集過擬合了
那么怎么解決這個問題呢? 解決的方式其實就是:我們需要將我們的問題分為三部分,這三部分分別是訓練數據集,驗證數據集,測試數據集。 我們使用訓練數據集訓練好模型之后,將驗證數據集送給這個模型,看看這個訓練數據集訓練的效果是怎么樣的,如果效果不好的話,我們重新換參數,重新訓練模型。直到我們的模型針對驗證數據來說已經達到最優了。 這樣我們的模型達到最優以后,再講測試數據集送給模型,這樣才能作為衡量模型最終的性能。換句話說,我們的測試數據集是不參與模型的創建的,而其他兩個數據集都參與了訓練。但是我們的測試數據集對于模型是完全不可知的,相當于我們在模型這個模型完全不知道的數據
這種方法還會有一個問題。由于我們的模型可能會針對驗證數據集過擬合,而我們只有一份驗證數據集,一旦我們的數據集里有比較極端的情況,那么模型的性能就會下降很多,那么為了解決這個問題,就有了交叉驗證。
交叉驗證 Cross Validation
交叉驗證相對來說是比較正規的、比較標準的在我們調整我們的模型參數的時候看我們的性能的方式
交叉驗證:在訓練模型的時候,通常把數據分成k份,例如分成3份(ABC)(分成k分,k屬于超參數),這三份分別作為驗證數據集和訓練數據集。這樣組合后可以分別產生三個模型,這三個模型,每個模型在測試數據集上都會產生一個性能的指標,這三個指標的平均值作為當前這個算法訓練處的模型衡量的標準是怎樣的。 由于我們有一個求平均的過程,所以不會由于一份驗證數據集中有比較極端的數據而導致模型有過大的偏差,這比我們只分成訓練、驗證、測試數據集要更加準確
Validation 和 Cross Validation
import numpy as np from sklearn import datasets digits = datasets.load_digits() X = digits.data y = digits.target測試train_test_split
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 KNeighborsClassifierbest_k, best_p, best_score = 0, 0, 0 # k為k近鄰中的尋找k個最近元素 for k in range(2, 11): # p為明科夫斯基距離的pfor p in range(1, 6):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_k, best_p, best_score = k, p, scoreprint("Best K =", best_k) print("Best P =", best_p) print("Best Score =", best_score) Best K = 3 Best P = 4 Best Score = 0.986091794159使用交叉驗證
# 使用sklearn提供的交叉驗證 from sklearn.model_selection import cross_val_scoreknn_clf = KNeighborsClassifier() # 返回的是一個數組,有三個元素,說明cross_val_score方法默認將我們的數據集分成了三份 # 這三份數據集進行交叉驗證后產生了這三個結果# cv默認為3,可以修改改參數,修改修改不同分數的數據集 cross_val_score(knn_clf,X_train,y_train,cv=3) array([ 0.98895028, 0.97777778, 0.96629213]) best_k, best_p, best_score = 0, 0, 0 for k in range(2, 11):for p in range(1, 6):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_k, best_p, best_score = k, p, scoreprint("Best K =", best_k) print("Best P =", best_p) print("Best Score =", best_score) Best K = 2 Best P = 2 Best Score = 0.982359987401通過觀察兩組調參過程的結果可以發現
1.兩組調參得出的參數結果是不同的,通常這時候我們更愿意詳細使用交叉驗證的方式得出的結果。
因為使用train_test_split很有可能只是過擬合了測試數據集得出的結果
2.使用交叉驗證得出的最好分數0.982是小于使用分割訓練測試數據集得出的0.986,因為在交叉驗證的
過程中,通常不會過擬合某一組的測試數據,所以平均來講這個分數會稍微低一些
但是使用交叉驗證得到的最好參數Best_score并不是真正的最好的結果,我們使用這種方式只是為了拿到
一組超參數而已,拿到這組超參數后我們就可以訓練處我們的最佳模型
回顧網格搜索
我們上面的操作,實際上在網格搜索的過程中已經進行了,只不過這個過程是sklean的網格搜索自帶的一個過程
from sklearn.model_selection import GridSearchCVparam_grid = [{'weights': ['distance'],'n_neighbors': [i for i in range(2, 11)], 'p': [i for i in range(1, 6)]} ]grid_search = GridSearchCV(knn_clf, param_grid, verbose=1) grid_search.fit(X_train, y_train) Fitting 3 folds for each of 45 candidates, totalling 135 fits[Parallel(n_jobs=1)]: Done 135 out of 135 | elapsed: 1.9min finished的意思就是交叉驗證中分割了三組數據集,而我們的參數組合為9*6=45中組合
3組數據集,45種組合,一共要進行135次的訓練.
cv參數
cross_val_score(knn_clf, X_train, y_train, cv=5) array([ 0.99543379, 0.96803653, 0.98148148, 0.96261682, 0.97619048]) # cv默認為3,可以修改改參數,修改修改不同分數的數據集 grid_search = GridSearchCV(knn_clf, param_grid, verbose=1, cv=5)總結
雖然整體速度慢了,但是這個結果卻是可信賴的
模型正則化-Regularization
什么是模型正則化
下圖是我們之前使用多項式回歸過擬合一個樣本的例子,可以看到這條模型曲線非常的彎曲,而且非常的陡峭,可以想象這條曲線的一些θ系數會非常的大。 模型正則化需要做的事情就是限制這些系數的大小
模型正則化基本原理
一些需要注意的細節:
嶺回歸 Ridge Regression
編程實現嶺回歸
嶺回歸 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) plt.show() from sklearn.pipeline import Pipeline from sklearn.preprocessing import PolynomialFeatures from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LinearRegressiondef PolynomialRegression(degree):return Pipeline([("poly", PolynomialFeatures(degree=degree)),("std_scaler", StandardScaler()),("lin_reg", LinearRegression())]) from sklearn.model_selection import train_test_splitnp.random.seed(666) X_train, X_test, y_train, y_test = train_test_split(X, y) from sklearn.metrics import mean_squared_errorpoly_reg = PolynomialRegression(degree=20) poly_reg.fit(X_train, y_train)y_poly_predict = poly_reg.predict(X_test) mean_squared_error(y_test, y_poly_predict) 167.94010867293571 X_plot = np.linspace(-3, 3, 100).reshape(100, 1) y_plot = poly_reg.predict(X_plot)plt.scatter(x, y) plt.plot(X_plot[:,0], y_plot, color='r') plt.axis([-3, 3, 0, 6]) plt.show()將繪制封裝成函數
def plot_model(model):X_plot = np.linspace(-3, 3, 100).reshape(100, 1)y_plot = model.predict(X_plot)plt.scatter(x, y)plt.plot(X_plot[:,0], y_plot, color='r')plt.axis([-3, 3, 0, 6])plt.show()plot_model(poly_reg)使用嶺回歸
from sklearn.linear_model import Ridgedef RidgeRegression(degree, alpha):return Pipeline([("poly", PolynomialFeatures(degree=degree)),("std_scaler", StandardScaler()),("ridge_reg", Ridge(alpha=alpha))]) # 注意alpha后面的參數是所有theta的平方和,而對于多項式回歸來說,嶺回歸之前得到的θ都非常大 # 我們前面系數alpha可以先取的小一些(正則化程度輕一些) # 第一個參數是degree20, 0.0001是第二個參數alpha ridge1_reg = RidgeRegression(20, 0.0001) ridge1_reg.fit(X_train, y_train)y1_predict = ridge1_reg.predict(X_test) mean_squared_error(y_test, y1_predict) 1.3233492754051845 # 通過使用嶺回歸,使得我們的均方誤差小了非常多,曲線也緩和了非常多 plot_model(ridge1_reg) ridge2_reg = RidgeRegression(20, 1) ridge2_reg.fit(X_train, y_train)y2_predict = ridge2_reg.predict(X_test) mean_squared_error(y_test, y2_predict) 1.1888759304218448 # 讓ridge2_reg 的alpha值等于1,均差誤差更加的縮小,并且曲線越來越趨近于一根傾斜的直線 plot_model(ridge2_reg) ridge3_reg = RidgeRegression(20, 100) ridge3_reg.fit(X_train, y_train)y3_predict = ridge3_reg.predict(X_test) mean_squared_error(y_test, y3_predict) 1.3196456113086197 # 得到的誤差依然是比較小,但是比之前的1.18大了些,說明正則化做的有些過頭了 plot_model(ridge3_reg) ridge4_reg = RidgeRegression(20, 10000000) ridge4_reg.fit(X_train, y_train)y4_predict = ridge4_reg.predict(X_test) mean_squared_error(y_test, y4_predict) 1.8408455590998372 # 當alpha非常大,我們的模型實際上相當于就是在優化θ的平方和這一項,使得其最小(因為MSE的部分相對非常小) # 而使得θ的平方和最小,就是使得每一個θ都趨近于0,這個時候曲線就趨近于一根直線了 plot_model(ridge4_reg)LASSO回歸
使用|θ|代替θ2來標示θ的大小
Selection Operator – 選擇運算符
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) plt.show() from sklearn.model_selection import train_test_splitnp.random.seed(666) X_train, X_test, y_train, y_test = train_test_split(X, y) from sklearn.pipeline import Pipeline from sklearn.preprocessing import PolynomialFeatures from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LinearRegressiondef PolynomialRegression(degree):return Pipeline([("poly", PolynomialFeatures(degree=degree)),("std_scaler", StandardScaler()),("lin_reg", LinearRegression())]) from sklearn.metrics import mean_squared_errorpoly_reg = PolynomialRegression(degree=20) poly_reg.fit(X_train, y_train)y_predict = poly_reg.predict(X_test) mean_squared_error(y_test, y_predict) 167.94010867293571 def plot_model(model):X_plot = np.linspace(-3, 3, 100).reshape(100, 1)y_plot = model.predict(X_plot)plt.scatter(x, y)plt.plot(X_plot[:,0], y_plot, color='r')plt.axis([-3, 3, 0, 6])plt.show()plot_model(poly_reg) from sklearn.linear_model import Lassodef LassoRegression(degree, alpha):return Pipeline([("poly", PolynomialFeatures(degree=degree)),("std_scaler", StandardScaler()),("lasso_reg", Lasso(alpha=alpha))]) lasso1_reg = LassoRegression(20, 0.01) lasso1_reg.fit(X_train, y_train)y1_predict = lasso1_reg.predict(X_test) mean_squared_error(y_test, y1_predict) 1.1496080843259966 plot_model(lasso1_reg) lasso2_reg = LassoRegression(20, 0.1) lasso2_reg.fit(X_train, y_train)y2_predict = lasso2_reg.predict(X_test) mean_squared_error(y_test, y2_predict) 1.1213911351818648 plot_model(lasso2_reg) lasso3_reg = LassoRegression(20, 1) lasso3_reg.fit(X_train, y_train)y3_predict = lasso3_reg.predict(X_test) mean_squared_error(y_test, y3_predict) 1.8408939659515595 plot_model(lasso3_reg)總結Ridge和Lasso
α=100的時候,使用Ridge的得到的模型曲線依舊是一根曲線,事實上,使用Ridge很難得到一根傾斜的直線,他一直是彎曲的形狀。
但是使用LASSO的時候,當α=0.1,雖然得到的依然是一根曲線,但是他顯然比Radge的程度更低,更像一根直線。
這是因為LASSO趨向于使得一部分theta值為0(而不是很小的值),所以可以作為特征選擇用,LASSO的最后兩個字母SO就是Selection Operator的首字母縮寫 使用LASSO的過程如果某一項θ等于0了,就說明LASSO Regression認為這個θ對應的特征是沒有用的,剩下的那些不等于0的θ就說明LASSO Regression認為對應的這些特征有用,所以他可以當做特征選擇用。
L1 范數常常用于特征選擇
L2 范數常常用于防止模型過擬合
http://t.hengwei.me/post/%E6%B5%85%E8%B0%88l0l1l2%E8%8C%83%E6%95%B0%E5%8F%8A%E5%85%B6%E5%BA%94%E7%94%A8.html#1-l0-%E8%8C%83%E6%95%B0
https://zhuanlan.zhihu.com/p/29360425
總結
以上是生活随笔為你收集整理的机器学习----多项式回归的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: XiaoHu日志 6/29~7/30
- 下一篇: 【数字图像处理】图像感兴趣区域与图像放大