目錄
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折驗證

該目的就是讓評估模型更加準确。
對應的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
...
執行個體
後面在進行補充對應的執行個體,因為看到網上的例子都是以随機森林的執行個體,是以我想先了解下随機森林再來看
總結
對于貝葉斯優化的執行個體後面會進行補充。加油吧