過擬合和欠擬合
有了多項(xiàng)式回歸的方式,我們就可以對(duì)非線性的數(shù)據(jù)做擬合了,不過,復(fù)雜度不夠的多項(xiàng)式回歸會(huì)導(dǎo)致欠擬合問題,而過度地使用多項(xiàng)式回歸又會(huì)導(dǎo)致過擬合問題。
接下來直觀地看一下什么是過擬合和欠擬合,生成模擬數(shù)據(jù)集:
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,size=100)
plt.scatter(x,y)
plt.show()

用線性回歸對(duì)該數(shù)據(jù)做訓(xùn)練:
'''線性回歸'''
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X,y)
lin_reg.score(X,y) //out:0.49
用線性回歸對(duì)該數(shù)據(jù)訓(xùn)練后的R方值為0.49,顯然線性關(guān)系不明顯,因此用線性回歸是有很大誤差的。不過添加多項(xiàng)式特征后,特征畢竟變多了,用R方衡量來衡量不同特征的模型不太直觀,改用均方誤差衡量:
from sklearn.metrics import mean_squared_error
y_predict = lin_reg.predict(X)
mean_squared_error(y,y_predict)

線性回歸的均方誤差為3.03,再看一下二次多項(xiàng)式回歸:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
def PolynomialRegression(degree):
'''傳入步驟對(duì)應(yīng)的類組成多項(xiàng)式回歸函數(shù)'''
return Pipeline([
("poly",PolynomialFeatures(degree=degree)),
("std_scaler",StandardScaler()),
("lin_reg",LinearRegression())
])
poly2_reg = PolynomialRegression(degree=2)
poly2_reg.fit(X,y)
y2_predict = poly2_reg.predict(X)
mean_squared_error(y,y2_predict)

二次多項(xiàng)式回歸的均方誤差要減小很多,擬合的曲線如下圖:

那更高次的呢?我們來試一試10次和100次。10次的情況:
'''修改degree測(cè)試'''
poly10_reg = PolynomialRegression(degree=10)
poly10_reg.fit(X,y)
y10_predict = poly10_reg.predict(X)
mean_squared_error(y,y10_predict)

10次冪的均方誤差相比2次又小了。擬合曲線如下圖:

100次的情況:
'''修改degree測(cè)試'''
poly100_reg = PolynomialRegression(degree=100)
poly100_reg.fit(X,y)
y100_predict = poly100_reg.predict(X)
mean_squared_error(y,y100_predict)

可見均方誤差更小了,擬合曲線如下圖:

不過上面只是一個(gè)100次冪的曲線將所有樣本特征點(diǎn)包括進(jìn)去,實(shí)際上這條連續(xù)曲線是這樣的:
plt.scatter(x,y)
plt.plot(X_plot,y_plot,color='r')#有序排序后繪制曲線
plt.axis([-3,3,-4,10])
plt.show()

理論上我們提高多項(xiàng)式的次數(shù)可以任意精度擬合樣本點(diǎn),從而樣本的均方誤差可以非常非常小,但是樣本誤差更小就真的能更好地表達(dá)數(shù)據(jù)走勢(shì)嗎?從圖像中看出顯然不能,這種現(xiàn)象是就是過擬合(overfitting),而只用一次線性回歸擬合的情況則是欠擬合。
機(jī)器學(xué)習(xí)主要解決的問題是過擬合,雖然過擬合的模型能使樣本誤差總體很小,但是在新的樣本上表現(xiàn)卻很差,泛化能力弱。而我們需要的是泛化能力強(qiáng)的模型而不是在樣本上誤差更小的模型。這也正是測(cè)試數(shù)據(jù)集的意義,將樣本分為訓(xùn)練和測(cè)試數(shù)據(jù)集,只用訓(xùn)練數(shù)據(jù)fit模型,而用測(cè)試數(shù)據(jù)測(cè)試模型。如果模型能在測(cè)試數(shù)據(jù)集同樣表現(xiàn)很好(有很小的誤差),說明模型效果不錯(cuò)??梢詼y(cè)試,如果將樣本劃分為訓(xùn)練集和測(cè)試集,10次冪,100次冪的多項(xiàng)式回歸雖然能使之在訓(xùn)練集上的誤差更小,但是在測(cè)試集上誤差卻是越來越大的,這正是過擬合導(dǎo)致的。
線性模型
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)

二次模型
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)

10次模型和100次模型


從上述結(jié)果發(fā)現(xiàn),在測(cè)試集上10次冪的誤差已大于2次冪的,而100次冪的誤差更是天文數(shù)字。綜上所述,欠擬合是算法所訓(xùn)練的模型不能完整表述數(shù)據(jù)關(guān)系,而過擬合是算法訓(xùn)練的模型過多地表達(dá)了數(shù)據(jù)間的關(guān)系(往往是把噪音當(dāng)成了特征,是噪音間的關(guān)系)。而我們需要尋找的是泛化能力最好的模型。
學(xué)習(xí)曲線
機(jī)器學(xué)習(xí)中有一個(gè)模型復(fù)雜度的概念,對(duì)于多項(xiàng)式回歸,次冪越高則復(fù)雜度越高,對(duì)于knn算法來說,k值越小模型復(fù)雜度越高。相應(yīng)地有模型復(fù)雜度曲線用于直觀地反映模型復(fù)雜度和模型準(zhǔn)確率的關(guān)系

不過模型復(fù)雜度曲線的繪制困難,這在后面的決策樹再具體介紹。這里我們先用一個(gè)學(xué)習(xí)曲線來直觀感受一下在多項(xiàng)式回歸中,模型復(fù)雜度和訓(xùn)練效果的關(guān)系。
線性模型
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,size=100)
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=10)#默認(rèn)0.25
X_train.shape
封裝學(xué)習(xí)曲線繪制函數(shù):
'''封裝學(xué)習(xí)曲線函數(shù)'''
def plot_learning_curve(algo,X_train,X_test,y_train,y_test):
'''algo是模型'''
train_score = []
test_score = []
l = len(X_train)+1
for i in range(1,l):
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,l)],np.sqrt(train_score),label='train')
plt.plot([i for i in range(1,l)],np.sqrt(test_score),label='test')
plt.legend()
plt.axis([0,l,0,4])
plt.show()
plot_learning_curve(LinearRegression(),X_train,X_test,y_train,y_test)
繪制線性模型的學(xué)習(xí)曲線:

可以觀察到隨著訓(xùn)練的進(jìn)行(這里是不斷增加訓(xùn)練數(shù)據(jù)),訓(xùn)練集上的誤差會(huì)慢慢積累,積累到一定程度穩(wěn)定下來,測(cè)試集的誤差先升后慢慢降低到一定程度穩(wěn)定下來。
二次模型

二次模型與線性模型趨勢(shì)一樣,不過穩(wěn)定的位置較一次低而且在測(cè)試集上的曲線和訓(xùn)練集上的曲線距離小,因?yàn)?次確實(shí)是最優(yōu)的模型。
20次冪模型

測(cè)試集曲線和訓(xùn)練集曲線距離更大了,說明過擬合現(xiàn)象比較嚴(yán)重。我們要尋找的是有最好的泛化能力的模型。如何尋找最優(yōu)的模型,使模型擁有優(yōu)秀的泛化能力呢?這將在下篇介紹。