python调参工作都是干啥的_xgboost原理及调参方法-通俗易懂版本
xgboost是各種比賽中最常使用的方法,網上介紹非常多,但是大部分看起來都比較費勁,這篇文章我將通俗的講一下xgboost是在干什么,是怎么實現的,每一步的細節中要注意什么問題,達到理解—應用的程度,想了解具體理論的各位看官請移步其他文章。
1.xgboost原理
說起xgboost,我們不得不提一下GBDT,也就是梯度提升決策樹,這是一種基于樹的集成算法,至于什么方法構成了GBDT的決策樹,無非就是ID3、C4.5、C5.0、CART,最常用的就是那個CART,多棵樹的集合就構成了GBDT。其實GBDT是對殘差的擬合,什么意思呢?假設目標函數是9,第一棵樹預測為5,剩下4的誤差,那么下一顆樹繼續擬合4,直至誤差滿足我們的要求,這和xgboost的思路是一樣的。那么問題來了,有了GBDT為啥還要用xgboost呢,有一種說法是,GBDT的每一步優化都依賴于上一步的誤差,當大數據量的時候就太慢了,xgboost通過改變目標函數來避免了這個問題。
GBDT的目標函數是預測值和真實值差的累加,也就是誤差累加,可以看出每一步計算都依賴于上面所有步的誤差,效率比較低。xgboost自然要做出改進,怎么優化呢,一步步分解來看。
形式上,在目標函數后面加一個懲罰項:
xgboost目標函數
目標函數簡化,采用高數中的泰勒展開,回憶一下泰勒展開是什么:
泰勒展開模式
好了怎么應用到上面的目標函數中呢,先來確認f(x)是啥,這個f(x)是上面說的那個損失函數l(yi,),也就是我們只泰勒展開這個l(yi,)就行了,那么扎展開的時候我們需要知道這個
是什么,來看損失函數的形式,
是個常量我們上一步求的,可以當f(x)來看,其中x自然是變量
,求導也要對它求。f(xi)是這把我們求的,是導致函數值變化的原因,巧了這個
也表示變化的原因,那么他兩是一個東西。
現在能展開了吧,請看下式:
損失函數的泰勒展開
這不還是坑人嗎,怎么變得這么簡潔的,其實吧gi和hi是下面這樣的:
好了前面那個l,我們上一步不是求出來了嗎,把它忽略掉吧,損失函數變成這樣了:
損失函數的簡化形式
到了這一步,目標函數已經和上一步的損失無關了,也就是xgboost擺脫了GBDT的缺點,可以并行計算了,核心做法是做了個泰勒展開,但你以為xgboost就這樣了嗎,那你就太年輕了,繼續來看。
樹復雜度表達式展開
怎么還有個Ω沒給我解釋呢,別急啊,來了,這個Ω是表示樹的復雜度的,你想啊樹的復雜度能怎么表示,首先你得考慮葉子節點個數吧,然后xgboost人家考慮的更多一些,還把葉子節點的得分給考慮進去了,并且為了防止葉子節點太多影響你計算,給你加了個L2正則化,啥不懂L2正則化,自己去百度吧。同時為了平衡這兩個指標,人家還給加了兩個權重,是不是很貼心。
樹的復雜度的表示方法
等一下啊,道理我都明白,但是你能不能告訴我葉子節點得分是怎么算的。這個吧,其實對于單顆決策樹是很好理解的,如果是分類問題那么這個數就是0-1之間的一個數,代表的是樣本分到這個節點上的得分值,如果是回歸問題,那么這個值就是樣本的平均值。但是對于xgboost,我們都把決策樹的目標給改了,這個東西你不得算出來啊,計算方法在后邊說,就是一個最優目標函數對應一個最優得分值。
目標函數的整合,目標函數的兩個部分都知道咋回事了吧,把它放到一起吧,這樣的話我們才能看怎么去優化,合并以后的公式是這樣子的:
整合以后的目標函數形式
這個w好像能合并到一起啊,合到一起試試。
進一步整合目標函數
看上去頭暈眼花的,什么東西啊,能不能再簡單點,當然能。先這樣:
然后再這樣:
目標函數的最終形式
目標函數的優化,都到這一步了可以優化了吧,這里邊變量就剩葉子節點的得分了,我們來求導,得到下面這個東西:
目標函數的優化
等一下啊,這個w不就是前面說的葉子節點得分值,原來是這么算的,求這個其實就是為了求目標函數值。好了有了目標函數值,接下來干嘛。回頭想想我們的目標,我們現在知道要擬合的殘差,我們有特征,接下來我們要找一顆最優的樹進行樣本劃分啊,咋找,決策樹找最優劃分點不是算增益最大嗎,那么我們拿著這個目標函數去找最大的增益不就是現在這棵樹的目標了嗎。好了怎么算呢,看下面式子:
樹結構劃分標準
其實劃分算法太多了,有很多是為了提高效率的,這個就交給包內部去解決吧,我們知道他是要劃分樹了就好了。
如此循環往復,一個xgboost過程就完成了,其實大概就是拿到值先找到一顆差不多的樹,一看不行啊還有誤差啊,拿著這個誤差再去找一棵樹繼續擬合,等到擬合的差不多了,這些個樹就集成到一起進行劃分。那么xgboost是怎么預測的,其實一句話就可以理解,就是每棵樹葉子節點得分的加和,想想你的指標在每棵樹上都有滿足條件的劃分,如果劃分到那一類就把葉子節點的得分加起來。其實xgboost還有縮減和列取樣的問題,意思是防止過擬合,就是說每一步葉子節點的權重都要乘上一個系數,這樣的話使每棵樹葉子節點權重對結果影響不會太大,剩下更多的空間交給模型去擬合,還有一個列取樣其實是為了計算簡便,每次計算時從特征空間中選出幾個來構建樹。
2.python導入相關包
python簡直太友好了,可以直接調用xgboost包跑程序,我們要做的就是提取指標和調參,提取指標這個事我教不了你,得根據業務來,調參倒是有套路可尋。首先你要實現一個xgboost,你要知道你用什么工具去實現,python里有兩個包,一個就叫xgboost,另外一個是xgboost的sklearn接口,叫XGBClassifer。另外要調參還有一個并行的網格搜索包,sklearn里的GridSearchCV。其他還有一些包需要引入就是打打輔助。
import pandas as pd
import numpy as np
import xgboost as xgb
from xgboost.sklearn import XGBClassifier
from sklearn import cross_validation, metrics #交叉驗證和效果評估,其他模型也很常用。
from sklearn.grid_search import GridSearchCV #并行搜索,加快速度。
3.xgboost調參
準備工作已經做好了,接下來開始調參工作了,調參之前大家記得要做兩件件事,就是先把數據整理好,把模型搭建好。
3.1 搭建模型
簡單的很,已經引入了XGBClassifier,直接把相關默認參數設置好就可以了。
clf1 = XGBClassifier(learning_rate =0.1,
n_estimators=1000,
max_depth=5,
min_child_weight=1,
gamma=0,
subsample=0.8,
colsample_bytree=0.8,
objective= 'binary:logistic',
nthread=4,
scale_pos_weight=1,
seed=27)
3.2 參數解釋
我們看到在建立xgboost的模型時,有很多參數,這些參數是什么意思呢,我們來看一下。
一般參數
這些參數用來控制XGBoost的整體功能,是一些通用的設置,有的時候都不用調整。
(1)booster[默認gbtree]
每次迭代的模型選擇,有兩個gbtree:基于樹的模型和gbliner:線性模型,顯然我們一般都會選擇gbtree。
(2)silent[默認0]
是否開啟靜默模式,0為不開啟,1為開啟,開啟后不輸出任何信息,顯然這不利于我們調參,默認選0就好了。
(3)nthread[默認取最大線程數]
這個參數用來控制最大并行的線程數,如果你希望取得所有CPU的核,那么你就不用管它。
booster參數或者說樹的參數
這些參數是要重點調整的,比較重要,主要是用來控制每一步樹的生成。
(1)eta [default=0.3]
學習率參數,就是原理中說的縮減,保證每一顆樹對于結果的影響不太大,從而保證模型的效果。更新葉子節點權重時,乘以該系數,避免步長過大。參數值越大,越可能無法收斂。把學習率 eta 設置的小一些,小學習率可以使得后面的學習更加仔細。 典型值為0.01-0.2。
(2)min_child_weight [default=1]
大家對他的解釋是決定最小葉子節點樣本權重和,不太好理解??戳艘恍┙忉尩奈恼?#xff0c;這個值可以理解為H值,還記得H值嗎,就是損失函數對y(t-1)的二階導數和,那么如果損失函數是平方函數(回歸問題),這個就是1,如果是對數損失函數(分類問題),導數是a(1-a)的形式,a代表sigmoid函數,這樣的話當y預測值非常大的時候,這個式子的值接近于0,這當然是不好的,因此你要給他設定一個閾值,小于這個閾值就不分裂了?,F在可以解釋了,這個值代表所有樣本二階導數的和,和上邊說的葉子得分不是一個事,如果是回歸問題實際代表樣本個數,如果是分類問題實際代表a(1-a)所有樣本計算值的加和。
明白這個參數是啥以后,來看他是干嘛的,這個參數用于避免過擬合,當它的值較大時,可以避免模型學習到局部的特殊樣本。舉個栗子來說,對正負樣本不均衡時的 0-1 分類而言,假設 h 在 0.01 附近,min_child_weight 為 1 意味著葉子節點中最少需要包含 100 個樣本,實際是通過控制樣本數來控制過擬合的。你們應該看出來這個值越小越容易過擬合,需要通過cv進行調整優化。
(3)max_depth [default=6]
這個沒啥好說的,每棵樹的最大深度,也是用來避免過擬合的,max_depth越大,模型會學到更具體更局部的樣本,典型值3-10,要用cv調優。
(4)max_leaf_nodes
樹上最大節點的數量,和上面的那個參數一樣,如果定義了這個參數就會忽略掉max_depth參數,我們調優還是以max_depth為主吧。
(5)gamma[default=0]
一聽這種希臘字母就知道是個系數,在樹的葉子節點上作進一步分區所需的最小損失減少。越大,算法越保守。取值在[0,∞] 。通俗點講就是,這個節點還劃不劃分,先看看損失減不減少了再說。同樣需要cv調優。
(6)max_delta_step [default=0]
這參數限制每棵樹權重改變的最大步長。如果這個參數的值為0,那就意味著沒有約束。如果它被賦予了某個正值,那么它會讓這個算法更加保守。通常,這個參數不需要設置。但是當各類別的樣本十分不平衡時,它對邏輯回歸是很有幫助的。也就是說這個參數不用管啊。
(7)subsample [default=1]
樣本采樣用的,減小這個參數的值,算法會更加保守,避免過擬合,但是如果這個值設置得過小,它可能會導致欠擬合。典型值:0.5-1。既然有個范圍,給他個面子cv調優一把吧。
(8)colsample_bytree [default=1]
列采樣,就是選擇生成樹的特征,前面介紹過了,和設置縮減率一樣是為了干嘛來著,是為了防止過擬合的,一般設置為: 0.5-1 ,也要用cv擬合。
(9)colsample_bylevel[default=1]
等一下哈,這個怎么和上面參數這么像,哦,它是在上面樹的基礎上,對每一級進行分裂時對列(就是特征)進行采樣,大神們都說這個參數不用用了,用上面那個就行了。
(10)lambda [default=1]
又是個系數,這個是控制L2正則的,就是目標函數里的那個葉子節點得分前邊的系數,用不用看你自己了。
(11)alpha [default=0]
想必你也想到了吧,有L2就有L1,用不用全憑自己了。
(12) scale_pos_weight [default=1]
這個是控制樣本均衡與否的,如果是不均衡樣本,設置一個正數可以保證快速收斂,具體為什么,也沒人解釋,先留著吧。
(13)tree_method[default=’auto’]
還記得我說過樹的生成有很多方法吧,他們介紹的老復雜了,別看了,人家自動給我們打包好了,有三個可選的值, {‘auto’, ‘exact’, ‘approx’} ,分別對應 貪心算法(小數據集)/近似算法(大數據集) 。
大概就這么多吧,如果看到了別的,我再補充。
學習目標參數
這個是最后一類參數了,跟目標函數有關。
(1)objective [ default=reg:linear ]
這是返回目標函數值,這個東西包含的函數還挺多,默認是線形的。此外你還可以選擇:binary:logistic 二分類的邏輯回歸,返回預測的概率(不是類別)。multi:softmax 使用softmax的多分類器,返回預測的類別(不是概率)。在這種情況下,你還需要多設一個參數:num_class(類別數目)。multi:softprob 和multi:softmax參數一樣,但是返回的是每個數據屬于各個類別的概率。
(2)eval_metric[默認值取決于objective參數的取值]
也就是說怎么計算目標函數值,根據你目標函數的形式來,對于回歸問題,默認值是rmse,對于分類問題,默認值是error。比較典型的有(我直接截圖了懶得打字):
損失函數計算方法
你應該知道吧目標函數值和實際值之間的差距,就是這個參數要計算的重點。
(3)seed(default=0)
這個叫隨機數種子,還記得random包里那個seed嗎,這個參數就是為了可以使結果復現。
命令行參數
n_estimators 這個參數叫迭代次數,也就是說生成樹的個數。
更多參數
更多參數請移步官方文檔:xgboost官方文檔
知道了這些參數,想要弄明白調參是干啥,調整什么就很容易了,下面會結合例子來說明。
3.3 調參方法
先來推薦一個大哥的博客,這個鏈接里https://blog.csdn.net/u014465639/article/details/74351982寫了好幾種模型的調參方法,想要了解的不妨去看看。
開始之前,給大家介紹一個新朋友,這個東西可以很好的幫助我們進行調參,它是sklearn里的一個包,[sklearn.model_selection.GridSearchCV],我們調參就是基于這個包的。那么這個包怎么實現調參呢,來看一眼它的常用參數。
(1)estimator:優化器,也就是你建立的模型,這里自然就是xgboost模型,如果要對其他集成算法調優,那就寫其他模型了,注意模型需要初始化哦。
(2)param_grid:字典或者列表,一般用字典,請在這里輸入你要優化的參數值。
(3)scoring :用啥子估計誤差,如果不設置,那我沒辦法了,就用estimator的誤差來衡量吧。
有了上面的方法,我們還會怕調參數嗎,當然不會了,先設置好常用的參數,然后再依次調參。請注意,調參是有順序的,按照下面這個來。
1.n_estimators
叫迭代次數,也就是生成樹的個數。
cv_params = {'n_estimators': [400, 500, 600, 700, 800]}
other_params = {'learning_rate': 0.1, 'n_estimators': 500, 'max_depth': 5, 'min_child_weight': 1, 'seed': 0,
'subsample': 0.8, 'colsample_bytree': 0.8, 'gamma': 0, 'reg_alpha': 0, 'reg_lambda': 1}
咦,這里邊有n_estimators的值了,其實就是以他為基準進行挑選啊,首先給個基礎值進去,給誰啊,當然是建立的初始模型了。
model = xgb.XGBRegressor(**other_params)
然后跑一下模型,這個我最后統一說,反正最后給出一個最優值,但是我們設置的粒度太粗了,不能直接用,接下來細調,同樣方法跑一遍。
cv_params = {'n_estimators': [550, 575, 600, 650, 675]}
2.min_child_weight和max_depth
這兩個參數是控制樹生成的,樹的結構對于最終的結果影響還是很大的,所以這個放到第二個調整批次是應當的,兩個參數可以一起調。
cv_params = {'max_depth': [3, 4, 5, 6, 7, 8, 9, 10], 'min_child_weight': [1, 2, 3, 4, 5, 6]}
other_params = {'learning_rate': 0.1, 'n_estimators': 550, 'max_depth': 5, 'min_child_weight': 1,
'seed': 0,'subsample': 0.8, 'colsample_bytree': 0.8, 'gamma': 0, 'reg_alpha': 0, 'reg_lambda': 1}
3.gamma
控制節點分裂標準的。
cv_params = {'gamma': [0.1, 0.2, 0.3, 0.4, 0.5, 0.6]}
4.subsample和colsample_bytree
采樣的放一起,都是比例。
cv_params = {'subsample': [0.6, 0.7, 0.8, 0.9], 'colsample_bytree': [0.6, 0.7, 0.8, 0.9]}
reg_alpha和reg_lambda
正則化的指標,這里有一點需要注意你看這個寫法和上面原理好像不一樣啊,其實就是直接XGB包和XGB包的sklearn接口的區別,一般都調用sklearn接口,所以就寫成符合sklearn習慣的樣子了。
cv_params = {'reg_alpha': [0.05, 0.1, 1, 2, 3], 'reg_lambda': [0.05, 0.1, 1, 2, 3]}
6.learning_rate
學習率,每一葉子節點得分需要乘上這個數,一般比較小,從小的數字調起。
cv_params = {'learning_rate': [0.01, 0.05, 0.07, 0.1, 0.2]}
基本調參就告一段落了,這里需要特別指出一點就是調參可以提高模型性能,但是更重要的還是特征選擇,數據清洗,特征融合等工作,大家注意把基礎工作做好。
4.完整代碼
基礎數據啥的我就不列了啊,大概說一下概要吧,和網上的不一樣,我也是按照自己的想法做了一些省略。
#1.建立一個初步的模型,看一下效果怎么樣。
xgb1 = XGBClassifier(
learning_rate =0.1,
n_estimators=1000,
max_depth=5,
min_child_weight=1,
gamma=0,
subsample=0.8,
colsample_bytree=0.8,
objective= 'binary:logistic',
nthread=4,
scale_pos_weight=1,
seed=27)#經驗值
xgb_param = xgb1.get_xgb_params()#得到模型的參數
xgtrain = xgb.DMatrix(dtrain[predictors].values, label=dtrain[target].values)#轉換成原生xgboost需要的數據格式。
cvresult = xgb.cv(xgb_param, xgtrain, num_boost_round=alg.get_params()['n_estimators'], nfold=cv_folds,
metrics='auc', early_stopping_rounds=early_stopping_rounds, show_progress=False)#注意啊這是原生的模型自帶的,你只需傳參,cv_folds=5,表示5%的數據用于交叉驗證。這個cvresults返回訓練集和測試集的誤差,行數就是最大迭代的次數。
xgb1.set_params(n_estimators=cvresult.shape[0])
xgb1.fit(dtrain[predictors], dtrain['Disbursed'],eval_metric='auc')
dtrain_predictions = alg.predict(dtrain[predictors])#算準確率用的
dtrain_predprob = alg.predict_proba(dtrain[predictors])[:,1]#算auc用的
feat_imp = pd.Series(alg.booster().get_fscore()).sort_values(ascending=False)#算重要度的指標
#‘weight’ - the number of times a feature is used to split the data across all trees.‘gain’ - the average gain of the feature when it is used in trees.‘cover’ - the average coverage of the feature when it is used in trees.
#weight - 該特征在所有樹中被用作分割樣本的特征的次數。gain - 在所有樹中的平均增益。cover - 在樹中使用該特征時的平均覆蓋范圍。
#
#2開始按步驟調參用的XGBclassifer。
#第一步調優
params_test1 = {'n_estimators': [400, 500, 600, 700, 800]}
other_params = {'learning_rate': 0.1, 'n_estimators': 500, 'max_depth': 5, 'min_child_weight': 1, 'seed': 27,
'subsample': 0.8, 'colsample_bytree': 0.8, 'gamma': 0, 'reg_alpha': 0, 'reg_lambda': 1}
model = XGBClassfoer(**other_params)
optimized_XGB 1= GridSearchCV(estimator=model, param_grid=cv_params, scoring='r2', cv=5, verbose=1, n_jobs=4)
optimized_XGB.fit(X_train, y_train)
evalute_result = optimized_GBM.grid_scores_
##第二步調優
param_test2 = { 'max_depth':range(3,10,2), 'min_child_weight':range(1,6,2)}
optimized_XGB2= GridSearchCV(estimator = XGBClassifier( learning_rate =0.1, n_estimators=140, max_depth=5,
min_child_weight=1, gamma=0, subsample=0.8, colsample_bytree=0.8,
objective= 'binary:logistic', nthread=4, scale_pos_weight=1, seed=27), param_grid = param_test2, scoring='roc_auc',n_jobs=4,iid=False, cv=5)
optimized_XGB2.fit(train[predictors],train[target])
optimized_XGB2.grid_scores_, optimized_XGB2.best_params_, optimized_XGB2.best_score_
#依次類推,得到最后的最優參數集合,再建立模型用于預測
#3.最終模型
model = XGBClassifer(learning_rate=0.1, n_estimators=550, max_depth=4, min_child_weight=5, seed=27,
subsample=0.7, colsample_bytree=0.7, gamma=0.1, reg_alpha=1, reg_lambda=1)
model.fit(X_train, y_train)
ans = model.predict(X_test)
??以上就是本篇的所有內容,很多東西就是講思路,讓大家都知道怎么回事,準確性可能差點,如果你想有更深的理解,還是結合其他人的文章看看。
總結
以上是生活随笔為你收集整理的python调参工作都是干啥的_xgboost原理及调参方法-通俗易懂版本的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 卸载mongodb_【数据库】mongo
- 下一篇: python 函数重载_在Python中