天天看點

機器學習入門研究(七)-模型選擇與調優1.超參數搜尋2.超參數調優過程3.網絡搜尋4.随機搜尋5.貝葉斯優化算法總結

目錄

1.超參數搜尋

2.超參數調優過程

3.網絡搜尋

原理

交叉驗證

對應的sklearn 的API

執行個體

4.随機搜尋

原理

對應的sklearn的API

執行個體

5.貝葉斯優化算法

主要思想

PS先驗分布、後驗分布、似然估計

兩個過程

與網格搜尋、随機搜尋差別

可以做貝葉斯優化的API

執行個體

總結

在上次KNN算法中,其中有個K值,隻是随機取了一個數值來了解這個KNN算法的基本流程,那這個K值怎麼取會得到的模型最好呢?就涉及到模型的選擇與調優來接近這個問題

1.超參數搜尋

像剛才提到的KNN中的k值、決策樹的樹的數量或深度等,我們在使用這些算法的時候,都需要人工設定的參數,稱為超參數。每改變一次超參數,模型則需要重新訓練。

而參數就是在訓練模型中學習到一部分,比如回歸系統、神經網絡等,是通過模型訓練獲得的。

對于超參數的設定,如果人工設定過程比較複雜,是以利用網絡搜尋、随機搜尋、貝葉斯優化算法來尋找這個最優參數。

2.超參數調優過程

一般過程為:

1)将資料集劃分為訓練集、驗證集、測試集

2)選擇模型性能評價名額

3)用訓練集對模型進行訓練

4)在驗證集上對模型進行參數搜尋,用性能名額來評價參數好壞

5)選出最優參數

3.網絡搜尋

Grid Search。對模型預設幾種超參數組合,選出表現最好的參數,也稱為暴力搜尋。

為避免初始資料的劃分對結果的影響,采用交叉驗證來減少偶然性,一般交叉驗證和網格搜尋來配合使用得到最優參數。

原理

在一定區間内,循環周遊,嘗試每一種可能性,并計算其限制函數和目标函數的值,對滿足條件的點,逐個比較其目标函數的值,抛棄壞點,保留好點,最終得到最優解的近似解。

交叉驗證

cross validation 

在上次介紹KNN的時候在訓練模型的時候将資料集分成了訓練集和測試集,那對于交叉驗證就是将訓練集在進行分成訓練集和驗證集。

我們可以将訓練集分成4份,其中一份最為驗證集。經過四次驗證,每次都更換不同的驗證集,即取得4組模型的結果,取平均值作為最終結果。資料分成幾份就稱為幾折交叉驗證,像分成4份,則稱為4折驗證

機器學習入門研究(七)-模型選擇與調優1.超參數搜尋2.超參數調優過程3.網絡搜尋4.随機搜尋5.貝葉斯優化算法總結

該目的就是讓評估模型更加準确。

對應的sklearn 的API

sklearn.model-selection.GridSearchCV(estimator, param_grid, scoring=None,
                 n_jobs=None, iid='warn', refit=True, cv='warn', verbose=0,
                 pre_dispatch='2*n_jobs', error_score='raise-deprecating',
                 return_train_score=False)
           

其中參數如下:

參數 含義
estimator 執行個體化的預估器
param_grid 預估參數,以字典的形式傳入("n_neighbors":[1,3,5])
scoring

準确度的評價名額,預設的為None,使用的是score函數

也可以設定其他評價名額,如scoring=‘roc_auc’

n_jobs 并行數,預設為1,-1表示與CPU核數一緻
iid 預設為各個樣本fold機率分布一緻
refit 預設為True:程式會以交叉驗證訓練集得到最佳參數
cv 幾折交叉驗證,資料量大的時候,該值稍微小點
verbose 日志容長度,預設為0:不輸出訓練過程;1:偶爾輸出;>1每個子模型都輸出
pre_dispatch 指定總共分發的并行任務數。當n_jobs>1時,資料在每個運作點進行複制
error_socre

預設為raise-deprecating:在模型拟合過程中如果産生誤差,誤差分數會提高

numeric:如果産生誤差,fitfailed warning會提高

return_train_score 預設為True:交叉驗證結果中包含訓練得分

傳回值仍為預估器,傳回值裡面的參數如下:

傳回值 含義
best_params 最佳參數
best_score 最佳結果
best_estimator 最佳預估器
cv_results 交叉驗證結果

執行個體

結合上次總結的機器學習入門研究(六)-KNN算法中提到的給鸢尾花分類的例子,增加網格搜尋的方式來進行選擇k值。

def knn_iris_gscv():
    #添加網格搜尋和交叉驗證

    #用knn進行分類
    # 從sklearn.datasets中擷取到鸢尾花的資料集,使用load_*方法說明是一個比較小的資料集
    iris = load_iris()
    # 資料分成訓練集和測試集
    x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=10)

    # 為防止資料量級差别比較大,是以将資料進行無量綱化,這裡采用标準化
    standard = StandardScaler()
    x_train = standard.fit_transform(x_train)
    x_test = standard.fit_transform(x_test)

    # 為防止資料量級差别比較大,是以将資料進行無量綱化,這裡采用标準化
    standard = StandardScaler()
    x_train = standard.fit_transform(x_train)
    x_test = standard.fit_transform(x_test)

    # 傳入到knn進行訓練,得到模型
    classifier = KNeighborsClassifier()
    param_dict = {"n_neighbors":[1,3,5,7,9]}
   #加入網格搜尋和交叉驗證
    classifier = GridSearchCV(classifier,param_grid=param_dict,cv=4)
    classifier.fit(x_train,y_train)

    y_predict = classifier.predict(x_test)
    print("最佳參數 :",classifier.best_params_)
    print("最佳結果:",classifier.best_score_)
    print("最佳預估器:",classifier.best_estimator_)
    print("交叉驗證結果",classifier.cv_results_)
    print("準确度為:", classifier.score(x_test,y_test))

    return None
           

看下運作結果:

最佳參數 : {'n_neighbors': 7}
最佳結果: 0.9333333333333333
最佳預估器: KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
                     metric_params=None, n_jobs=None, n_neighbors=7, p=2,
                     weights='uniform')
交叉驗證結果 {'mean_fit_time': array([0.00062317, 0.00055081, 0.00054991, 0.00055623, 0.00057566]), 'std_fit_time': array([7.58426654e-05, 4.64360734e-05, 3.64887543e-05, 3.29138554e-05,
       5.62770125e-05]), 'mean_score_time': array([0.00291884, 0.00281823, 0.00283533, 0.00278461, 0.00289708]), 'std_score_time': array([2.21179304e-04, 1.79146338e-04, 9.36839974e-05, 9.96620318e-05,
       4.34642939e-05]), 'param_n_neighbors': masked_array(data=[1, 3, 5, 7, 9],
             mask=[False, False, False, False, False],
       fill_value='?',
            dtype=object), 'params': [{'n_neighbors': 1}, {'n_neighbors': 3}, {'n_neighbors': 5}, {'n_neighbors': 7}, {'n_neighbors': 9}], 'split0_test_score': array([0.90322581, 0.90322581, 0.90322581, 0.96774194, 0.96774194]), 'split1_test_score': array([0.9, 0.9, 0.9, 0.9, 0.9]), 'split2_test_score': array([0.83333333, 0.86666667, 0.86666667, 0.86666667, 0.83333333]), 'split3_test_score': array([0.93103448, 0.96551724, 0.96551724, 1.        , 0.96551724]), 'mean_test_score': array([0.89166667, 0.90833333, 0.90833333, 0.93333333, 0.91666667]), 'std_test_score': array([0.03573672, 0.03533239, 0.03533239, 0.05261955, 0.05528267]), 'rank_test_score': array([5, 3, 3, 1, 2], dtype=int32)}
準确度為: 0.9
           

我們可以看到當k值取到7時,分類效果最佳。

4.随機搜尋

Random Search。利用随機數去求函數近似的最優解的方法。

原理

在一定區間内,不斷随機産生随機點,并計算限制函數和目标函數的值,對滿足條件的點,逐個比較其目标函數的值,抛棄壞點,保留好點,最終得到最優解的近似解。

所取的機率點越多,則得到的最優解的機率越高。

效率要高于網格搜尋。

對應的sklearn的API

sklearn.model-selection.RandomizedSearchCV(estimator, param_distributions, n_iter=10, scoring=None,
                 n_jobs=None, iid='warn', refit=True,
                 cv='warn', verbose=0, pre_dispatch='2*n_jobs',
                 random_state=None, error_score='raise-deprecating',
                 return_train_score=False)
           

其中參數如下:

參數 含義
estimator 執行個體化的預估器
param_distributions 字典或清單,需要優化的參數的取值範圍
n_iter 抽樣參數,預設為10
scoring

準确度的評價名額,預設的為None,使用的是score函數

也可以設定其他評價名額,如scoring=‘roc_auc’

n_jobs 并行數,預設為1,-1表示與CPU核數一緻
iid 預設為各個樣本fold機率分布一緻
refit 預設為True:程式會以交叉驗證訓練集得到最佳參數
cv 幾折交叉驗證,資料量大的時候,該值稍微小點
verbose 日志容長度,預設為0:不輸出訓練過程;1:偶爾輸出;>1每個子模型都輸出
pre_dispatch 指定總共分發的并行任務數。當n_jobs>1時,資料在每個運作點進行複制
random_state

随機種子。

預設為None:np.random所使用的随機狀态執行個體

int值:随機狀态是随機數生成器所使用的種子;

随機執行個體:随機狀态是随機數生成器

error_socre

預設為raise-deprecating:在模型拟合過程中如果産生誤差,誤差分數會提高

numeric:如果産生誤差,fitfailed warning會提高

return_train_score 預設為True:交叉驗證結果中包含訓練得分

參數大多數和網格搜尋的類似,傳回值同網格搜尋。

執行個體

執行個體還是上次提到的鸢尾花的分類,其實唯一差別的就是将GridSearchCV換成了RandomizedSearchCV

from sklearn.model_selection import RandomizedSearchCV
def knn_iris_random():
    # 用knn進行分類
    # 從sklearn.datasets中擷取到鸢尾花的資料集,使用load_*方法說明是一個比較小的資料集
    iris = load_iris()
    # 資料分成訓練集和測試集
    x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=10)

    # 為防止資料量級差别比較大,是以将資料進行無量綱化,這裡采用标準化
    standard = StandardScaler()
    x_train = standard.fit_transform(x_train)
    x_test = standard.fit_transform(x_test)

    # 為防止資料量級差别比較大,是以将資料進行無量綱化,這裡采用标準化
    standard = StandardScaler()
    x_train = standard.fit_transform(x_train)
    x_test = standard.fit_transform(x_test)

    # 傳入到knn進行訓練,得到模型
    classifier = KNeighborsClassifier()
    param_dict = {"n_neighbors": range(1,10,2)}
    # 加入網格搜尋和交叉驗證
    classifier = RandomizedSearchCV(classifier, param_distributions=param_dict, cv=8)
    classifier.fit(x_train, y_train)

    y_predict = classifier.predict(x_test)
    print("最佳參數 :", classifier.best_params_)
    print("最佳結果:", classifier.best_score_)
    print("最佳預估器:", classifier.best_estimator_)
    print("交叉驗證結果", classifier.cv_results_)
    print("準确度為:", classifier.score(x_test, y_test))
    return None
           

輸出的結果如下:

最佳參數 : {'n_neighbors': 7}
最佳結果: 0.9583333333333334
最佳預估器: KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
                     metric_params=None, n_jobs=None, n_neighbors=7, p=2,
                     weights='uniform')
交叉驗證結果 {'mean_fit_time': array([0.00036195, 0.00031918, 0.00031105, 0.00030887, 0.00031501]), 'std_fit_time': array([3.97733068e-05, 1.15625330e-05, 9.55158621e-06, 8.84802795e-06,
       2.12870376e-05]), 'mean_score_time': array([0.0011453 , 0.00108483, 0.00104901, 0.00105032, 0.00106758]), 'std_score_time': array([9.20791837e-05, 6.29039349e-05, 2.34934375e-05, 2.43233512e-05,
       4.40424282e-05]), 'param_n_neighbors': masked_array(data=[1, 3, 5, 7, 9],
             mask=[False, False, False, False, False],
       fill_value='?',
            dtype=object), 'params': [{'n_neighbors': 1}, {'n_neighbors': 3}, {'n_neighbors': 5}, {'n_neighbors': 7}, {'n_neighbors': 9}], 'split0_test_score': array([1.    , 0.9375, 0.9375, 1.    , 1.    ]), 'split1_test_score': array([0.8125, 0.8125, 0.8125, 0.875 , 0.875 ]), 'split2_test_score': array([0.9375, 0.9375, 0.9375, 0.9375, 0.9375]), 'split3_test_score': array([0.93333333, 0.93333333, 0.93333333, 0.93333333, 0.93333333]), 'split4_test_score': array([1., 1., 1., 1., 1.]), 'split5_test_score': array([0.85714286, 0.85714286, 0.85714286, 0.92857143, 0.92857143]), 'split6_test_score': array([1.        , 1.        , 0.92857143, 1.        , 1.        ]), 'split7_test_score': array([0.92857143, 1.        , 1.        , 1.        , 1.        ]), 'mean_test_score': array([0.93333333, 0.93333333, 0.925     , 0.95833333, 0.95833333]), 'std_test_score': array([0.06554109, 0.06497099, 0.06029853, 0.04493161, 0.04493161]), 'rank_test_score': array([3, 3, 5, 1, 1], dtype=int32)}
準确度為: 0.9
           

5.貝葉斯優化算法

上面提到的網格搜尋或随機搜尋在測試一個新點的時候,會忽略前一個點的資訊,而貝葉斯優化則充分利用之前的點的資訊。貝葉斯優化算法通過對目标函數形狀進行學習,找到使目标函數向全局最優解提升的參數。

主要思想

給定優化的目标函數,通過不斷添加樣本點來更新目标函數的後驗分布,進而調整目前的參數。

通俗點:對目标函數形狀進行學習,找到使目标函數向全局最大提升的參數。

具體學習目标函數的方法:

(1)首先根據先驗分布,假設一個搜尋函數;

(2)每一次使用新的采樣點來測試目标函數,利用這個資訊更新目标函數的先驗分布;

(3)算法測試有後驗分布給出全局最優解最可能出現的位置點。

PS先驗分布、後驗分布、似然估計

參照部落格https://blog.csdn.net/qq_40597317/article/details/82388164 了解下什麼是先驗分布、後驗分布、似然估計。

  • 先驗分布

對未知參數x的先驗資訊用一個分布形式p(x)來表示。可以了解為對某個原因的經驗推斷。

舉例1:

測量自己的體重,在測量之前就知道自己體重不會超過120斤,不會低于90斤,這個推斷可以了解為生活經驗所得。

舉例2:

老王會走路、騎自行車、或開車去某個地方。假設大家都知道老王是一個健身達人。

那麼老王開車去的可能性就比較小,跑步去的可能性就比較大,這個就可以了解為常識得到的先驗分布。

  • 後驗分布

知道事情的結果,然後根據結果推測原因,即該結果由某個原因出現的機率為後驗機率。

舉例:

還是剛才的老王要去10公裡外的地方辦事,他可以走路、騎自行車、或者開車,并且花了一定時間才到了目的地。

在這個事件中可以把走路、騎自行車、或開車作為原因,花了一定時間作為結果。

老王花了1小時完成了10公裡,則很可能是騎自行車過去,很小可能性跑步,或者開車堵車。

老王花了2小時完成了10公裡,則很有可能是走路

花了20分鐘,很有可能是開車

先知道結果,然後根據結果估計原因,則稱為後驗分布。

  • 似然估計

與後驗分布相反,根據原因推斷該原因導緻結果發生的機率。

舉例:

還是剛才老王,決定步行過去,很有可能10公裡需要2個小時;

較小可能性跑步1小時過去;

更有可能騎自行車1小時過去

先确定原因,根據原因來估計結果的機率分布。

兩個過程

(1)高斯過程:用以拟合優化目标函數模組化,得到其後驗分布;

(2)貝葉斯優化:嘗試抽樣進行樣本計算,在局部最優解上不斷采樣。

貝葉斯優化又分為探索(exploration)和利用(exploitation)兩個過程,即進行高效采樣。

  • 探索就是在還未取樣區域去擷取采樣點;探索意味着方差高
  • 開發就是根據後驗分布在最可能出現全局最優解的區域去進行采樣;開發意味着均值高

貝葉斯優化一旦找到局部最優解,就會在該區域不斷采樣,容易陷入局部最優解。是以為了彌補這個缺陷,貝葉斯優化算法會在探索(exploration)和利用(exploitation)之間找一個平衡點,基于資料使用貝葉斯定理估計目标的後驗分布,然後根據分布選擇下一個采樣的超參數組合。

與網格搜尋、随機搜尋差別

(1)貝葉斯優化采用高斯過程,考慮之前的參數,不斷更新先驗分布;而網格搜尋或随機搜尋并沒有考慮;

(2)貝葉斯優化疊代次數少,速度快;而網格搜尋或随機搜尋速度慢,參數過多時,容易導緻次元爆炸;

(3)貝葉斯優化針對非凸問題依然穩健;而網格搜尋或随機搜尋對非凸問題得到局部最優

貝葉斯優化缺點在于高斯過程核矩陣不好選

可以做貝葉斯優化的API

BayesianOptimization
bayesopt
skopt
hyperopt
...
           

執行個體

後面在進行補充對應的執行個體,因為看到網上的例子都是以随機森林的執行個體,是以我想先了解下随機森林再來看

總結

對于貝葉斯優化的執行個體後面會進行補充。加油吧

繼續閱讀