在實際訓練中,模型一般對訓練數據好,可是對訓練數據以外的數據擬合程度差。用於評價模型的泛化能力,從而進行模型選擇。html
把在某種意義下將原始數據(dataset)進行分組,一部分作爲訓練集(train set),另外一部分作爲驗證集(validation set or test set),首先用訓練集對模型進行訓練,再利用驗證集來測試模型的泛化偏差。另外,現實中數據老是有限的,爲了對數據造成重用,從而提出k-摺疊交叉驗證。python
對於個分類或迴歸問題,假設可選的模型爲M={M1,M2,M3……Md}。k-摺疊交叉驗證就是將訓練集的1/k做爲測試集,每一個模型訓練k次,測試k次,錯誤率爲k次的平均,最終選擇平均率最小的模型Mi。git
一、 將所有訓練集S分紅k個不相交的子集,假設S中的訓練樣例個數爲m,那麼每個子集有m/k個訓練樣例,相應的子集稱做{S1,S2,S3……Sk}。github
二、 每次從模型集合M中拿出來一個Mi,而後在訓練子集中選擇出k-1個算法
{S1,S2,Sj-1,Sj+1,Sk}(也就是每次只留下一個Sj),使用這k-1個子集訓練Mi後,獲得假設函數hij。最後使用剩下的一份Sj做測試,獲得經驗錯誤。數組
三、 因爲咱們每次留下一個Sj(j從1到k),所以會獲得k個經驗錯誤,那麼對於一個Mi,它的經驗錯誤是這k個經驗錯誤的平均。dom
四、 選出平均經驗錯誤率最小的Mi,而後使用所有的S再作一次訓練,獲得最後的hi。機器學習
K折交叉驗證函數
GridSearchCV用於系統地遍歷多種參數組合,經過交叉驗證肯定最佳效果參數。工具
classsklearn.model_selection.GridSearchCV(estimator,param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True,cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score='raise',return_train_score=True)
經常使用參數解讀
estimator:所使用的分類器,如estimator=RandomForestClassifier(min_samples_split=100, min_samples_leaf=20, max_depth=8, max_features='sqrt', random_state=10)
而且傳入除須要肯定最佳的參數以外的其餘參數。每個分類器都須要一個scoring參數,或者score方法。
param_grid:值爲字典或者列表,即須要最優化的參數的取值,param_item = {'n_estimators':range(10,71,10)} param_grid =param_item
scoring :準確度評價標準,默認None,這時須要使用score函數;或者如scoring=’roc_auc’,根據所選模型不一樣,評價準則不一樣。字符串(函數名),或是可調用對象,須要其函數簽名形如:scorer(estimator, X, y);若是是None,則使用estimator的偏差估計函數。
cv :交叉驗證參數,默認None,使用三折交叉驗證。指定fold數量,默認爲3,也能夠是yield訓練/測試數據的生成器。
refit :默認爲True,程序將會以交叉驗證訓練集獲得的最佳參數,從新對全部可用的訓練集與開發集進行,做爲最終用於性能評估的最佳模型參數。即在搜索參數結束後,用最佳參數結果再次fit一遍所有數據集。
iid:默認True,爲True時,默認爲各個樣本fold機率分佈一致,偏差估計爲全部樣本之和,而非各個fold的平均。
verbose:日誌冗長度,int:冗長度,0:不輸出訓練過程,1:偶爾輸出,>1:對每一個子模型都輸出。
n_jobs: 並行數,int:個數,-1:跟CPU核數一致, 1:默認值。
pre_dispatch:指定總共分發的並行任務數。當n_jobs大於1時,數據將在每一個運行點進行復制,這可能致使OOM,而設置pre_dispatch參數,則能夠預先劃分總共的job數量,使數據最多被複制pre_dispatch次
儘管使用參數設置的網格法是目前最普遍使用的參數優化方法, 其餘搜索方法也具備更有利的性能。 RandomizedSearchCV 實現了對參數的隨機搜索, 其中每一個設置都是從可能的參數值的分佈中進行取樣。 這對於窮舉搜索有兩個主要優點:
指定如何取樣的參數是使用字典完成的, 很是相似於爲 GridSearchCV 指定參數。 此外, 經過 n_iter 參數指定計算預算, 即取樣候選項數或取樣迭代次數。 對於每一個參數, 能夠指定在可能值上的分佈或離散選擇的列表 (均勻取樣):
{'C': scipy.stats.expon(scale=100), 'gamma': scipy.stats.expon(scale=.1), 'kernel': ['rbf'], 'class_weight':['balanced', None]}
搜索的輸出值
cv_results_:給出不一樣參數狀況下的評價結果的記錄
best_params_:描述了已取得最佳結果的參數的組合
best_score_:成員提供優化過程期間觀察到的最好的評分
from sklearn.datasets import load_iris # 自帶的樣本數據集 from sklearn.neighbors import KNeighborsClassifier # 要估計的是knn裏面的參數,包括k的取值和樣本權重分佈方式 import matplotlib.pyplot as plt # 可視化繪圖 from sklearn.model_selection import GridSearchCV,RandomizedSearchCV # 網格搜索和隨機搜索 iris = load_iris() X = iris.data # 150個樣本,4個屬性 y = iris.target # 150個類標號 ####################################################### k_range = range(1, 30) # 優化參數k的取值範圍 weight_options = ['uniform', 'distance'] # 代估參數權重的取值範圍。uniform爲統一取權值,distance表示距離倒數取權值 # 下面是構建parameter grid,其結構是key爲參數名稱,value是待搜索的數值列表的一個字典結構 params = {'n_neighbors':k_range,'weights':weight_options} # 定義優化參數字典,字典中的key值必須是分類算法的函數的參數名 knn = KNeighborsClassifier(n_neighbors=5) # 定義分類算法。n_neighbors和weights的參數名稱和params字典中的key名對應
# ================================網格搜索======================================= # 這裏GridSearchCV的參數形式和cross_val_score的形式差很少,其中params是 parameter grid所對應的參數 # GridSearchCV中的n_jobs設置爲-1時,能夠實現並行計算(若是你的電腦支持的狀況下) grid = GridSearchCV(estimator = knn, param_grid = params, cv=10, scoring='accuracy') #針對每一個參數對進行了10次交叉驗證。scoring='accuracy'使用準確率爲結果的度量指標。能夠添加多個度量指標 grid.fit(X, y) #print('網格搜索-度量記錄:',grid.cv_results_) # 包含每次訓練的相關信息 print('網格搜索-最佳度量值:',grid.best_score_) # 獲取最佳度量值 print('網格搜索-最佳參數:',grid.best_params_) # 獲取最佳度量值時的代定參數的值。是一個字典 print('網格搜索-最佳模型:',grid.best_estimator_) # 獲取最佳度量時的分類器模型 # 使用獲取的最佳參數生成模型,預測數據 knn_grid = KNeighborsClassifier(n_neighbors=grid.best_params_['n_neighbors'], weights=grid.best_params_['weights']) # 取出最佳參數進行建模 knn_grid.fit(X, y) # 訓練模型 print(knn_grid.predict([[3, 5, 4, 2]])) # 預測新對象
# =====================================隨機搜索=========================================== rand = RandomizedSearchCV(knn, params, cv=10, scoring='accuracy', n_iter=10, random_state=5) # rand.fit(X, y) #print('隨機搜索-度量記錄:',grid.cv_results_) # 包含每次訓練的相關信息 print('隨機搜索-最佳度量值:',grid.best_score_) # 獲取最佳度量值 print('隨機搜索-最佳參數:',grid.best_params_) # 獲取最佳度量值時的代定參數的值。是一個字典 print('隨機搜索-最佳模型:',grid.best_estimator_) # 獲取最佳度量時的分類器模型 # 使用獲取的最佳參數生成模型,預測數據 knn_random = KNeighborsClassifier(n_neighbors=grid.best_params_['n_neighbors'], weights=grid.best_params_['weights']) # 取出最佳參數進行建模 knn_random.fit(X, y) # 訓練模型 print(knn_random.predict([[3, 5, 4, 2]])) # 預測新對象
當你的調節參數是連續的,好比迴歸問題的正則化參數,有必要指定一個連續分佈而不是可能值的列表,這樣RandomizeSearchCV就能夠執行更好的grid search。
http://hyperopt.github.io/hyperopt-sklearn/
Hyperopt庫爲python中的模型選擇和參數優化提供了算法和並行方案。機器學習常見的模型有KNN, SVM,PCA,決策樹,GBDT等一系列的算法,可是在實際應用中,咱們須要選取合適的模型,並對模型調參,獲得一組合適的參數。尤爲是在模型的調參階段,須要花費大量的時間和精力,卻又效率低下。可是咱們能夠換一個角度來看待這個問題,模型的選取,以及模型中須要調節的參數,能夠看作是一組變量,模型的質量標準(好比正確率,AUC)等等能夠看作是目標函數,這個問題就是超參數的優化的問題。咱們可使用搜索算法來解決。
若是咱們要肯定某個算法模型的最佳參數,一般會使用網格搜索(GridSearch),即假若有兩個參數A和B,它們分別有NA和NB個取值(人爲設定),那麼咱們則須要依次枚舉這些取值的全部組合狀況(在這裏是共NA∗NB
種),而後取準確率最高的那一個做爲最終這個算法模型的最優參數。
顯然,若是要枚舉的組合狀況很是多,網格搜索將變得十分低效,甚至不可接受。那麼本文要介紹的hyperopt能夠理解爲一個智能化的網格搜索,能大大縮短調參所需的時間。
#!/usr/bin/env python # encoding: utf-8 """ @version: v1.0 @author: zwqjoy @contact: zwqjoy@163.com @site: https://blog.csdn.net/zwqjoy @file: para @time: 2018/7/7 17:00 """ from hyperopt import fmin, tpe, hp, rand import numpy as np from sklearn.metrics import accuracy_score from sklearn import svm from sklearn import datasets # SVM的三個超參數:C爲懲罰因子,kernel爲核函數類型,gamma爲核函數的額外參數(對於不一樣類型的核函數有不一樣的含義) # 有別於傳統的網格搜索(GridSearch),這裏只須要給出最優參數的機率分佈便可,而不須要按照步長把具體的值給一個個枚舉出來 parameter_space_svc ={ # loguniform表示該參數取對數後符合均勻分佈 'C':hp.loguniform("C", np.log(1), np.log(100)), 'kernel':hp.choice('kernel',['rbf','poly']), 'gamma': hp.loguniform("gamma", np.log(0.001), np.log(0.1)), } # 鳶尾花卉數據集,是一類多重變量分析的數據集 # 經過花萼長度,花萼寬度,花瓣長度,花瓣寬度4個屬性預測鳶尾花卉屬於(Setosa,Versicolour,Virginica)三個種類中的哪一類 iris = datasets.load_digits() #--------------------劃分訓練集和測試集-------------------- train_data = iris.data[0:1300] train_target = iris.target[0:1300] test_data = iris.data[1300:-1] test_target = iris.target[1300:-1] #----------------------------------------------------------- # 計數器,每一次參數組合的枚舉都會使它加1 count = 0 def function(args): print(args) # **能夠把dict轉換爲關鍵字參數,能夠大大簡化複雜的函數調用 clf = svm.SVC(**args) # 訓練模型 clf.fit(train_data,train_target) # 預測測試集 prediction = clf.predict(test_data) global count count = count + 1 score = accuracy_score(test_target,prediction) print("[{0}], Test acc: {1})".format(str(count), score)) # 因爲hyperopt僅提供fmin接口,所以若是要求最大值,則須要取相反數 return -score # algo指定搜索算法,目前支持如下算法: # ①隨機搜索(hyperopt.rand.suggest) # ②模擬退火(hyperopt.anneal.suggest) # ③TPE算法(hyperopt.tpe.suggest,算法全稱爲Tree-structured Parzen Estimator Approach) # max_evals指定枚舉次數上限,即便第max_evals次枚舉仍未能肯定全局最優解,也要結束搜索,返回目前搜索到的最優解 best = fmin(function, parameter_space_svc, algo=tpe.suggest, max_evals=100) # best["kernel"]返回的是數組下標,所以須要把它還原回來 kernel_list = ['rbf','poly'] best["kernel"] = kernel_list[best["kernel"]] print("best params: ",best) clf = svm.SVC(**best) print(clf)
注意:
tuning with Hyperopt- TypeError: 'generator' object has no attribute '__getitem__'
The issue is incompatibility of Hyperopt with networkxx2. One needs to downgrade to "networkx 1.11". (pip intall networkx==1.11)
參考: