Scikit-Learn學習筆記——模型驗證與超引數網格搜尋
阿新 • • 發佈:2019-02-17
超引數與模型驗證
模型驗證就是在選擇模型和超引數之後,通過對訓練資料進行學習,對比模型對已知資料的預測值與實際值的差異。模型驗證的正確方法是使用留出集評估模型效能,即先從訓練模型中的資料中留出一部分,然後用這部分留出來的資料檢驗模型效能。
但是,使用留出集使得模型失去了一部分訓練機會,解決這個問題的方法是交叉驗證,也就是做一組擬合,讓資料的每個子集既是訓練集,又是驗證集。
#使用sklearn API實現交叉驗證
#使用k近鄰分類器,資料是鳶尾花資料集
from sklearn.datasets import load_iris
from sklearn.cross_validation import cross_val_score
from sklearn.neighbors import KNeighborsClassifier
iris = load_iris()
x = iris.data
y = iris.target
model = KNeighborsClassifier(n_neighbors=1)
cross_val_score(model, x, y, cv=5)
#輸出結果
Out[20]: array([0.96666667, 0.96666667, 0.93333333, 0.93333333, 1. ])
Scikit-Learn為不同的應用場景提供了各種交叉驗證方法,都以迭代器形式在corss_validation模組中實現。例如,我們每次只用一個樣本做測試,其他樣本全用於訓練。這種交叉檢驗型別成為LOO(leave-one-out)交叉驗證。
from sklearn.cross_validation import LeaveOneOut
scores = cross_val_score(model, x, y, cv=LeaveOneOut(len(x)))
scores.mean()
#輸出結果
0.96
選擇最優模型
“最優模型”的問題基本上可以看成是找出偏差和方差的平衡點的問題。使用複雜度較低的模型(高偏差)時,訓練資料往往欠擬合,說明模型對訓練資料和新資料都缺乏預測能力。而使用複雜度較高的模型(高方差)時,訓練資料往往過擬合,說明模型對訓練資料預測能力強,但是對新資料的預測能力很很差。當使用複雜度適中的模型時,驗證曲線得分很高。說明再該模型複雜度條件下,偏差與方差達到均衡狀態。
scikit-learn驗證曲線
#用三種多項式迴歸模型來擬合同一份資料
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import make_pipeline
#使用管道命令來實現一個帶多項式前處理器的簡單線性迴歸模型
def PolynomialRegression(degree=2, **kwargs):
return make_pipeline(PolynomialFeatures(degree), LinearRegression(**kwargs))
#產生資料
import numpy as np
def make_data(N, err=1.0, rseed=1):
rng = np.random.RandomState(rseed)
X = rng.rand(N, 1) ** 2
y = 10 - 1./(X.ravel() + 0.1)
if err > 0:
y += err * rng.randn(N)
return X, y
X,y = make_data(40)
#視覺化資料和三種多項式擬合曲線
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn; seaborn.set()
x_test = np.linspace(-0.1, 1.1, 500)[:, None]
plt.scatter(X.ravel(), y, color='black')
axis = plt.axis()
for degree in [1,3,5]:
y_predict = PolynomialRegression(degree).fit(X, y).predict(x_test)
plt.plot(x_test.ravel(), y_predict, '-c',label='degree={0}'.format(degree))
plt.xlim(-0.1, 1.0)
plt.ylim(-2, 12)
plt.legend(loc='best')
#利用validation_curve函式視覺化驗證曲線。只要提供模型、資料、引數和驗證範圍資訊,
#函式就能自動計算驗證範圍內的訓練得分和驗證得分
from sklearn.learning_curve import validation_curve
degree = np.arange(0, 21)
train_score, val_score = validation_curve(PolynomialRegression(), X, y,
'polynomialfeatures__degree', degree, cv=7)
plt.plot(degree, np.median(train_score, 1), color='blue', label='training score')
plt.plot(degree, np.median(val_score, 1), color='red', label='validation score')
plt.legend(loc='best')
plt.ylim(0, 1)
plt.xlabel('degree')
plt.ylabel('score')
學習曲線
反映訓練集規模的訓練得分/驗證的得分曲線被稱為學習曲線,學習曲線的特徵包括以下三點:
- 特定複雜度的模型對較小的資料集容易過擬合:此時訓練得分較高,驗證得分較低。
- 特定複雜度的模型對較大的資料集容易欠擬合:隨著資料的增大,訓練得分會不斷降低,而驗證的份額你會不斷升高
- 模型的驗證集得分不會高於訓練得分:兩條曲線一直在靠近,但永遠不會交叉。
- 最重要的特徵是,隨著訓練樣本數量的增加,分數會收斂到定值。因此,一旦你的資料多到使模型得分已經收斂,那麼增加更多的訓練樣本也無濟於事!改善模型效能的唯一方法就是換模型。
#計算不同多項式階數下模型的學習曲線
from sklearn.learning_curve import learning_curve
fig, ax = plt.subplots(1,2,figsize=(16, 6))
fig.subplots_adjust(left=0.0625, right=0.95, wspace=0.1)
for i, degree in enumerate([2,9]):
N, train_lc, val_lc = learning_curve(PolynomialRegression(degree), X, y, cv=7,
train_sizes=np.linspace(0.3, 1, 25))
ax[i].plot(N, np.mean(train_lc, 1), color='blue', label='tranning score')
ax[i].plot(N, np.mean(val_lc, 1), color='red', label='validation score')
ax[i].hlines(np.mean([train_lc[-1], val_lc[-1]]), N[0], N[-1], color='gray', linestyle='dashed')
ax[i].set_ylim(0,1)
ax[i].set_xlim(N[0], N[-1])
ax[i].set_xlabel('trainning size')
ax[i].set_ylabel('score')
ax[i].set_title('degree={0}'.format(degree), size=14)
ax[i].legend(loc='best')
選擇模型的超引數
上面的例子只比較了多項式次數為2和9時的學習曲線,實際情況是改變學習曲線的因素不只有多項式次數這一種變數,這使得搜尋最佳的模型超引數變得困難複雜。Scikit-Learn的grid_search提供了一個自動化工具解決這個問題。下面使用網格搜尋尋找最優多項式迴歸模型的示例。我們將在模型特徵的三維網路中尋找最優值——包括多項式的次數的搜尋範圍,迴歸模型時候符合截距,以及迴歸模型是否需要進行標準化處理。
from sklearn.grid_search import GridSearchCV
param_grid = {'polynomialfeatures__degree':np.arange(21),
'linearregression__fit_intercept':[True, False],
'linearregression__normalize': [True, False]}
grid = GridSearchCV(PolynomialRegression(), param_grid, cv=7)
#呼叫fit()方法在每個網格點上擬合模型,並同時記錄每個點的得分
grid.fit(X, y);
print(grid.best_params_)
#輸出結果
{'linearregression__fit_intercept': False, 'linearregression__normalize': True, 'polynomialfeatures__degree': 4}
model = grid.best_estimator_
#繪製最優模型下的擬合曲線
plt.scatter(X.ravel(), y)
lim = plt.axis()
y_test = model.fit(X, y).predict(x_test)
plt.plot(x_test.ravel(), y_test, hold=True)
plt.axis(lim);