1. 程式人生 > >Scikit-Learn學習筆記——模型驗證與超引數網格搜尋

Scikit-Learn學習筆記——模型驗證與超引數網格搜尋

超引數與模型驗證

模型驗證就是在選擇模型和超引數之後,通過對訓練資料進行學習,對比模型對已知資料的預測值與實際值的差異。模型驗證的正確方法是使用留出集評估模型效能,即先從訓練模型中的資料中留出一部分,然後用這部分留出來的資料檢驗模型效能。

但是,使用留出集使得模型失去了一部分訓練機會,解決這個問題的方法是交叉驗證,也就是做一組擬合,讓資料的每個子集既是訓練集,又是驗證集。

#使用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);

這裡寫圖片描述