過擬合和欠擬合
有了多項式回歸的方式胖齐,我們就可以對非線性的數(shù)據(jù)做擬合了,不過舰涌,復(fù)雜度不夠的多項式回歸會導(dǎo)致欠擬合問題,而過度地使用多項式回歸又會導(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()
用線性回歸對該數(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
用線性回歸對該數(shù)據(jù)訓(xùn)練后的R方值為0.49朱躺,顯然線性關(guān)系不明顯,因此用線性回歸是有很大誤差的哺徊。不過添加多項式特征后室琢,特征畢竟變多了乾闰,用R方衡量來衡量不同特征的模型不太直觀落追,改用均方誤差衡量:
from sklearn.metrics import mean_squared_error
y_predict = lin_reg.predict(X)
mean_squared_error(y,y_predict)
線性回歸的均方誤差為3.03,再看一下二次多項式回歸:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
def PolynomialRegression(degree):
'''傳入步驟對應(yī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)
二次多項式回歸的均方誤差要減小很多涯肩,擬合的曲線如下圖:
那更高次的呢轿钠?我們來試一試10次和100次。10次的情況:
'''修改degree測試'''
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測試'''
poly100_reg = PolynomialRegression(degree=100)
poly100_reg.fit(X,y)
y100_predict = poly100_reg.predict(X)
mean_squared_error(y,y100_predict)
可見均方誤差更小了疗垛,擬合曲線如下圖:
不過上面只是一個100次冪的曲線將所有樣本特征點包括進(jìn)去,實際上這條連續(xù)曲線是這樣的:
plt.scatter(x,y)
plt.plot(X_plot,y_plot,color='r')#有序排序后繪制曲線
plt.axis([-3,3,-4,10])
plt.show()
理論上我們提高多項式的次數(shù)可以任意精度擬合樣本點硫朦,從而樣本的均方誤差可以非常非常小贷腕,但是樣本誤差更小就真的能更好地表達(dá)數(shù)據(jù)走勢嗎?從圖像中看出顯然不能咬展,這種現(xiàn)象是就是過擬合(overfitting)泽裳,而只用一次線性回歸擬合的情況則是欠擬合。
機(jī)器學(xué)習(xí)主要解決的問題是過擬合破婆,雖然過擬合的模型能使樣本誤差總體很小涮总,但是在新的樣本上表現(xiàn)卻很差,泛化能力弱祷舀。而我們需要的是泛化能力強(qiáng)的模型而不是在樣本上誤差更小的模型瀑梗。這也正是測試數(shù)據(jù)集的意義,將樣本分為訓(xùn)練和測試數(shù)據(jù)集裳扯,只用訓(xùn)練數(shù)據(jù)fit模型抛丽,而用測試數(shù)據(jù)測試模型。如果模型能在測試數(shù)據(jù)集同樣表現(xiàn)很好(有很小的誤差)饰豺,說明模型效果不錯铺纽。可以測試哟忍,如果將樣本劃分為訓(xùn)練集和測試集狡门,10次冪,100次冪的多項式回歸雖然能使之在訓(xùn)練集上的誤差更小锅很,但是在測試集上誤差卻是越來越大的其馏,這正是過擬合導(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)爆安,在測試集上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í)中有一個模型復(fù)雜度的概念儿倒,對于多項式回歸,次冪越高則復(fù)雜度越高呜笑,對于knn算法來說夫否,k值越小模型復(fù)雜度越高。相應(yīng)地有模型復(fù)雜度曲線用于直觀地反映模型復(fù)雜度和模型準(zhǔn)確率的關(guān)系
不過模型復(fù)雜度曲線的繪制困難叫胁,這在后面的決策樹再具體介紹凰慈。這里我們先用一個學(xué)習(xí)曲線來直觀感受一下在多項式回歸中,模型復(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)練集上的誤差會慢慢積累,積累到一定程度穩(wěn)定下來输钩,測試集的誤差先升后慢慢降低到一定程度穩(wěn)定下來豺型。
二次模型
二次模型與線性模型趨勢一樣,不過穩(wěn)定的位置較一次低而且在測試集上的曲線和訓(xùn)練集上的曲線距離小张足,因為2次確實是最優(yōu)的模型触创。
20次冪模型
測試集曲線和訓(xùn)練集曲線距離更大了,說明過擬合現(xiàn)象比較嚴(yán)重为牍。我們要尋找的是有最好的泛化能力的模型哼绑。如何尋找最優(yōu)的模型,使模型擁有優(yōu)秀的泛化能力呢碉咆?這將在下篇介紹抖韩。