gbdt調參的小結


關鍵部分轉自http://www.cnblogs.com/pinard/p/6143927.html

第一次知道網格搜索這個方法,不知道在工業中是不是用這種方式

1.首先從步長和迭代次數入手,選擇一個較大的步長,和較小的迭代次數。可以將步長設置為0.1,迭代次數從20-100網格搜索。

2.找到最合適的迭代次數,對決策樹最大深度max_depth和內部節點再划分所需最少樣本數min_samples_split進行網格搜索,最大深度3-15,樣本100-800。

3.找到一個最大深度,由於min_samples_split還與葉子結點最少樣本數min_samples_leaf有關,所以讓這兩個參數一起網格搜索調參。

4.找到最佳min_samples_split和min_samples_leaf,接下來對最大特征數max_features調參,可以使用百分數或者絕對數來進行網格搜索.

5.接下來對子采樣比例進行網格搜索。

6.現在基本上得到了所有的參數,現在就調小步長,調大迭代次數來增大模型的泛化能力。可以多嘗試幾次。

1. scikit-learn GBDT類庫概述

    在sacikit-learn中,GradientBoostingClassifier為GBDT的分類類, 而GradientBoostingRegressor為GBDT的回歸類。兩者的參數類型完全相同,當然有些參數比如損失函數loss的可選擇項並不相同。這些參數中,類似於Adaboost,我們把重要參數分為兩類,第一類是Boosting框架的重要參數,第二類是弱學習器即CART回歸樹的重要參數。

    下面我們就從這兩個方面來介紹這些參數的使用。

2. GBDT類庫boosting框架參數

    首先,我們來看boosting框架相關的重要參數。由於GradientBoostingClassifier和GradientBoostingRegressor的參數絕大部分相同,我們下面會一起來講,不同點會單獨指出。

    1) n_estimators: 也就是弱學習器的最大迭代次數,或者說最大的弱學習器的個數。一般來說n_estimators太小,容易欠擬合,n_estimators太大,又容易過擬合,一般選擇一個適中的數值。默認是100。在實際調參的過程中,我們常常將n_estimators和下面介紹的參數learning_rate一起考慮。

    2) learning_rate: 即每個弱學習器的權重縮減系數νν,也稱作步長,在原理篇的正則化章節我們也講到了,加上了正則化項,我們的強學習器的迭代公式為fk(x)=fk1(x)+νhk(x)fk(x)=fk−1(x)+νhk(x)。νν的取值范圍為0<ν10<ν≤1。對於同樣的訓練集擬合效果,較小的νν意味着我們需要更多的弱學習器的迭代次數。通常我們用步長和迭代最大次數一起來決定算法的擬合效果。所以這兩個參數n_estimators和learning_rate要一起調參。一般來說,可以從一個小一點的νν開始調參,默認是1。

    3) subsample: 即我們在原理篇的正則化章節講到的子采樣,取值為(0,1]。注意這里的子采樣和隨機森林不一樣,隨機森林使用的是放回抽樣,而這里是不放回抽樣。如果取值為1,則全部樣本都使用,等於沒有使用子采樣。如果取值小於1,則只有一部分樣本會去做GBDT的決策樹擬合。選擇小於1的比例可以減少方差,即防止過擬合,但是會增加樣本擬合的偏差,因此取值不能太低。推薦在[0.5, 0.8]之間,默認是1.0,即不使用子采樣。

    4) init: 即我們的初始化的時候的弱學習器,擬合對應原理篇里面的f0(x)f0(x),如果不輸入,則用訓練集樣本來做樣本集的初始化分類回歸預測。否則用init參數提供的學習器做初始化分類回歸預測。一般用在我們對數據有先驗知識,或者之前做過一些擬合的時候,如果沒有的話就不用管這個參數了。

    5) loss: 即我們GBDT算法中的損失函數。分類模型和回歸模型的損失函數是不一樣的。

      對於分類模型,有對數似然損失函數"deviance"和指數損失函數"exponential"兩者輸入選擇。默認是對數似然損失函數"deviance"。在原理篇中對這些分類損失函數有詳細的介紹。一般來說,推薦使用默認的"deviance"。它對二元分離和多元分類各自都有比較好的優化。而指數損失函數等於把我們帶到了Adaboost算法。

      對於回歸模型,有均方差"ls", 絕對損失"lad", Huber損失"huber"和分位數損失“quantile”。默認是均方差"ls"。一般來說,如果數據的噪音點不多,用默認的均方差"ls"比較好。如果是噪音點較多,則推薦用抗噪音的損失函數"huber"。而如果我們需要對訓練集進行分段預測的時候,則采用“quantile”。

    6) alpha:這個參數只有GradientBoostingRegressor有,當我們使用Huber損失"huber"和分位數損失“quantile”時,需要指定分位數的值。默認是0.9,如果噪音點較多,可以適當降低這個分位數的值。

3. GBDT類庫弱學習器參數

    這里我們再對GBDT的類庫弱學習器的重要參數做一個總結。由於GBDT使用了CART回歸決策樹,因此它的參數基本來源於決策樹類,也就是說,和DecisionTreeClassifier和DecisionTreeRegressor的參數基本類似。如果你已經很熟悉決策樹算法的調參,那么這一節基本可以跳過。不熟悉的朋友可以繼續看下去。

    1) 划分時考慮的最大特征數max_features: 可以使用很多種類型的值,默認是"None",意味着划分時考慮所有的特征數;如果是"log2"意味着划分時最多考慮log2Nlog2N個特征;如果是"sqrt"或者"auto"意味着划分時最多考慮N−−√N個特征。如果是整數,代表考慮的特征絕對數。如果是浮點數,代表考慮特征百分比,即考慮(百分比xN)取整后的特征數。其中N為樣本總特征數。一般來說,如果樣本特征數不多,比如小於50,我們用默認的"None"就可以了,如果特征數非常多,我們可以靈活使用剛才描述的其他取值來控制划分時考慮的最大特征數,以控制決策樹的生成時間。

    2) 決策樹最大深度max_depth: 默認可以不輸入,如果不輸入的話,決策樹在建立子樹的時候不會限制子樹的深度。一般來說,數據少或者特征少的時候可以不管這個值。如果模型樣本量多,特征也多的情況下,推薦限制這個最大深度,具體的取值取決於數據的分布。常用的可以取值10-100之間。

    3) 內部節點再划分所需最小樣本數min_samples_split: 這個值限制了子樹繼續划分的條件,如果某節點的樣本數少於min_samples_split,則不會繼續再嘗試選擇最優特征來進行划分。 默認是2.如果樣本量不大,不需要管這個值。如果樣本量數量級非常大,則推薦增大這個值。

    4) 葉子節點最少樣本數min_samples_leaf: 這個值限制了葉子節點最少的樣本數,如果某葉子節點數目小於樣本數,則會和兄弟節點一起被剪枝。 默認是1,可以輸入最少的樣本數的整數,或者最少樣本數占樣本總數的百分比。如果樣本量不大,不需要管這個值。如果樣本量數量級非常大,則推薦增大這個值。

    5)葉子節點最小的樣本權重和min_weight_fraction_leaf:這個值限制了葉子節點所有樣本權重和的最小值,如果小於這個值,則會和兄弟節點一起被剪枝。 默認是0,就是不考慮權重問題。一般來說,如果我們有較多樣本有缺失值,或者分類樹樣本的分布類別偏差很大,就會引入樣本權重,這時我們就要注意這個值了。

    6) 最大葉子節點數max_leaf_nodes: 通過限制最大葉子節點數,可以防止過擬合,默認是"None”,即不限制最大的葉子節點數。如果加了限制,算法會建立在最大葉子節點數內最優的決策樹。如果特征不多,可以不考慮這個值,但是如果特征分成多的話,可以加以限制,具體的值可以通過交叉驗證得到。

    7) 節點划分最小不純度min_impurity_split:  這個值限制了決策樹的增長,如果某節點的不純度(基於基尼系數,均方差)小於這個閾值,則該節點不再生成子節點。即為葉子節點 。一般不推薦改動默認值1e-7。

4. 調參實例

數據下載地址http://files.cnblogs.com/files/pinard/train_modified.zip

  1 import pandas as pd
  2 import numpy as np
  3 from sklearn.ensemble import GradientBoostingClassifier
  4 from sklearn import cross_validation, metrics
  5 from sklearn.grid_search import GridSearchCV
  6 
  7 import matplotlib.pylab as plt
  8 #%matplotlib inline
  9 train = pd.read_csv('train_modified.csv')
 10 target='Disbursed' # Disbursed的值就是二元分類的輸出
 11 IDcol = 'ID'
 12 print(train['Disbursed'].value_counts()) 
 13 x_columns = [x for x in train.columns if x not in [target, IDcol]]
 14 X = train[x_columns]
 15 y = train['Disbursed']
 16 '''
 17 gbm0 = GradientBoostingClassifier(random_state=10)
 18 gbm0.fit(X,y)
 19 y_pred = gbm0.predict(X)
 20 y_predprob = gbm0.predict_proba(X)[:,1]
 21 print ("Accuracy : %.4g" % metrics.accuracy_score(y.values, y_pred))
 22 print ("AUC Score (Train): %f" % metrics.roc_auc_score(y, y_predprob))
 23 '''
 24 '''
 25 1.首先我們從步長(learning rate)和迭代次數(n_estimators)入手。
 26 一般來說,開始選擇一個較小的步長來網格搜索最好的迭代次數。
 27 這里,我們將步長初始值設置為0.1。對於迭代次數進行網格搜索如下:
 28 '''
 29 '''
 30 param_test1 = {'n_estimators': range(20,81,10) }#[20,30,40,50,60,70,80,90,100,110,200]
 31 gsearch1 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, min_samples_split=300,
 32                                   min_samples_leaf=20,max_depth=8,max_features='sqrt', subsample=0.8,random_state=10), 
 33                        param_grid = param_test1, scoring='roc_auc',iid=False,cv=5)
 34 gsearch1.fit(X,y)
 35 print(gsearch1.grid_scores_, gsearch1.best_params_, gsearch1.best_score_)
 36 '''
 37 #得到最佳迭代次數60
 38 '''
 39 2.找到了一個合適的迭代次數,現在我們開始對決策樹進行調參。
 40  首先我們對決策樹最大深度max_depth和內部節點再划分所需最小樣本數min_samples_split進行網格搜索。
 41 '''
 42 '''
 43 param_test2 = {'max_depth':[3,5,7,9,11,13], 'min_samples_split':[100,300,500,700]}
 44 gsearch2 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, n_estimators=60, min_samples_leaf=20, 
 45       max_features='sqrt', subsample=0.8, random_state=10), 
 46    param_grid = param_test2, scoring='roc_auc',iid=False, cv=5)
 47 gsearch2.fit(X,y)
 48 print(gsearch2.grid_scores_, gsearch2.best_params_, gsearch2.best_score_)
 49 '''
 50 #得到最佳樹深度7
 51 '''
 52 3.由於決策樹深度7是一個比較合理的值,我們把它定下來,對於內部節點再划分所需最小樣本數min_samples_split,
 53 我們暫時不能一起定下來,因為這個還和決策樹其他的參數存在關聯。
 54 下面我們再對內部節點再划分所需最小樣本數min_samples_split和葉子節點最少樣本數min_samples_leaf一起調參。
 55 '''
 56 '''
 57 param_test3 = {'min_samples_split':[800,1000,1200,1400,1600,1800],
 58 'min_samples_leaf':[40,50,60,70,80,90,100]}
 59 gsearch3 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, n_estimators=60,max_depth=7,
 60                                      max_features='sqrt', subsample=0.8, random_state=10), 
 61                        param_grid = param_test3, scoring='roc_auc',iid=False, cv=5)
 62 gsearch3.fit(X,y)
 63 print(gsearch3.grid_scores_, gsearch3.best_params_, gsearch3.best_score_)
 64 '''
 65 #得到最佳min_samples_leaf = 60;min_samples_split = 1200
 66 #我們調了這么多參數了,終於可以都放到GBDT類里面去看看效果了。現在我們用新參數擬合數據:
 67 '''
 68 gbm1 = GradientBoostingClassifier(learning_rate=0.1,n_estimators=60,max_depth=7,
 69                                   min_samples_leaf=60,min_samples_split=1200,
 70                                   max_features='sqrt',subsample=0.8,random_state=10)
 71 gbm1.fit(X,y)
 72 y_pred = gbm1.predict(X)
 73 y_predprob = gbm1.predict_proba(X)[:,1]
 74 print ("Accuracy : %.4g" % metrics.accuracy_score(y.values, y_pred))
 75 print ("AUC Score (Train): %f" % metrics.roc_auc_score(y, y_predprob))
 76 '''
 77 '''
 78 4.對比我們最開始完全不調參的擬合效果,可見精確度稍有下降,主要原理是我們使用了0.8的子采樣,20%的數據沒有參與擬合。
 79 現在我們再對最大特征數max_features進行網格搜索。
 80 '''
 81 '''
 82 param_test4 = {'max_features':[7,9,11,13,15,17,19]}
 83 gsearch4 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, n_estimators=60,max_depth=7, min_samples_leaf =60, 
 84                min_samples_split =1200, subsample=0.8, random_state=10), 
 85                        param_grid = param_test4, scoring='roc_auc',iid=False, cv=5)
 86 gsearch4.fit(X,y)
 87 print(gsearch4.grid_scores_, gsearch4.best_params_, gsearch4.best_score_)
 88 '''
 89 #得到最佳特征數9
 90 '''
 91 5.現在我們再對子采樣的比例進行網格搜索:
 92 '''
 93 '''
 94 param_test5 = {'subsample':[0.6,0.7,0.75,0.8,0.85,0.9]}
 95 gsearch5 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, n_estimators=60,max_depth=7, min_samples_leaf =60, 
 96                min_samples_split =1200, max_features=9, random_state=10), 
 97                        param_grid = param_test5, scoring='roc_auc',iid=False, cv=5)
 98 gsearch5.fit(X,y)
 99 print(gsearch5.grid_scores_, gsearch5.best_params_, gsearch5.best_score_)
100 '''
101 ##得到最佳子采樣比例0.7
102 '''
103 現在我們基本已經得到我們所有調優的參數結果了。
104 6.這時我們可以減半步長,最大迭代次數加倍來增加我們模型的泛化能力。再次擬合我們的模型:
105 '''
106 '''
107 gbm2 = GradientBoostingClassifier(learning_rate=0.05, n_estimators=120,max_depth=7, min_samples_leaf =60, 
108                min_samples_split =1200, max_features=9, subsample=0.7, random_state=10)
109 gbm2.fit(X,y)
110 y_pred = gbm2.predict(X)
111 y_predprob = gbm2.predict_proba(X)[:,1]
112 print("Accuracy : %.4g" % metrics.accuracy_score(y.values, y_pred))
113 print("AUC Score (Train): %f" % metrics.roc_auc_score(y, y_predprob))
114 '''
115 '''
116 可以看到AUC分數比起之前的版本稍有下降,這個原因是我們為了增加模型泛化能力,
117 為防止過擬合而減半步長,最大迭代次數加倍,同時減小了子采樣的比例,從而減少了訓練集的擬合程度。
118 7.下面我們繼續將步長縮小5倍,最大迭代次數增加5倍,繼續擬合我們的模型:
119 '''
120 '''
121 gbm3 = GradientBoostingClassifier(learning_rate=0.01, n_estimators=600,max_depth=7, min_samples_leaf =60, 
122                min_samples_split =1200, max_features=9, subsample=0.7, random_state=10)
123 gbm3.fit(X,y)
124 y_pred = gbm3.predict(X)
125 y_predprob = gbm3.predict_proba(X)[:,1]
126 print ("Accuracy : %.4g" % metrics.accuracy_score(y.values, y_pred))
127 print ("AUC Score (Train): %f" % metrics.roc_auc_score(y, y_predprob))
128 '''
129 #由輸出,可見減小步長增加迭代次數可以在保證泛化能力的基礎上增加一些擬合程度。
130 '''8.最后我們繼續步長縮小一半,最大迭代次數增加2倍,擬合我們的模型:'''
131 gbm4 = GradientBoostingClassifier(learning_rate=0.005, n_estimators=1200,max_depth=7, min_samples_leaf =60, 
132                min_samples_split =1200, max_features=9, subsample=0.7, random_state=10)
133 gbm4.fit(X,y)
134 y_pred = gbm4.predict(X)
135 y_predprob = gbm4.predict_proba(X)[:,1]
136 print ("Accuracy : %.4g" % metrics.accuracy_score(y.values, y_pred))
137 print ("AUC Score (Train): %f" % metrics.roc_auc_score(y, y_predprob))
138 '''輸出如下,此時由於步長實在太小,導致擬合效果反而變差,也就是說,步長不能設置的過小。'''
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM