轉自http://www.cnblogs.com/pinard/p/6160412.html
1. scikit-learn隨機森林類庫概述
在scikit-learn中,RF的分類類是RandomForestClassifier,回歸類是RandomForestRegressor。當然RF的變種Extra Trees也有, 分類類ExtraTreesClassifier,回歸類ExtraTreesRegressor。由於RF和Extra Trees的區別較小,調參方法基本相同,本文只關注於RF的調參。
和GBDT的調參類似,RF需要調參的參數也包括兩部分,第一部分是Bagging框架的參數,第二部分是CART決策樹的參數。下面我們就對這些參數做一個介紹。
2. RF框架參數
首先我們關注於RF的Bagging框架的參數。這里可以和GBDT對比來學習。在scikit-learn 梯度提升樹(GBDT)調參小結中我們對GBDT的框架參數做了介紹。GBDT的框架參數比較多,重要的有最大迭代器個數,步長和子采樣比例,調參起來比較費力。但是RF則比較簡單,這是因為bagging框架里的各個弱學習器之間是沒有依賴關系的,這減小的調參的難度。換句話說,達到同樣的調參效果,RF調參時間要比GBDT少一些。
下面我來看看RF重要的Bagging框架的參數,由於RandomForestClassifier和RandomForestRegressor參數絕大部分相同,這里會將它們一起講,不同點會指出。
1) n_estimators: 也就是弱學習器的最大迭代次數,或者說最大的弱學習器的個數。一般來說n_estimators太小,容易欠擬合,n_estimators太大,又容易過擬合,一般選擇一個適中的數值。默認是100。在實際調參的過程中,我們常常將n_estimators和下面介紹的參數learning_rate一起考慮。
2) oob_score :即是否采用袋外樣本來評估模型的好壞。默認識False。個人推薦設置為True,因為袋外分數反應了一個模型擬合后的泛化能力。
3) criterion: 即CART樹做划分時對特征的評價標准。分類模型和回歸模型的損失函數是不一樣的。分類RF對應的CART分類樹默認是基尼系數gini,另一個可選擇的標准是信息增益。回歸RF對應的CART回歸樹默認是均方差mse,另一個可以選擇的標准是絕對值差mae。一般來說選擇默認的標准就已經很好的。
從上面可以看出, RF重要的框架參數比較少,主要需要關注的是 n_estimators,即RF最大的決策樹個數。
3. RF決策樹參數
下面我們再來看RF的決策樹參數,它要調參的參數基本和GBDT相同,如下:
1) RF划分時考慮的最大特征數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。
上面決策樹參數中最重要的包括最大特征數max_features, 最大深度max_depth, 內部節點再划分所需最小樣本數min_samples_split和葉子節點最少樣本數min_samples_leaf。
4.RF調參實例
這里仍然使用GBDT調參時同樣的數據集來做RF調參的實例,數據的下載地址在這。本例我們采用袋外分數來評估我們模型的好壞。
1 import pandas as pd 2 import numpy as np 3 from sklearn.ensemble import RandomForestClassifier 4 from sklearn.grid_search import GridSearchCV 5 from sklearn import cross_validation, metrics 6 import matplotlib.pylab as plt 7 8 #我們把解壓的數據用下面的代碼載入,順便看看數據的類別分布。 9 train = pd.read_csv('train_modified.csv') 10 target='Disbursed' # Disbursed的值就是二元分類的輸出 11 IDcol = 'ID' 12 print(train['Disbursed'].value_counts() ) 13 14 #選擇好樣本特征和類別輸出 15 x_columns = [x for x in train.columns if x not in [target, IDcol]] 16 X = train[x_columns] 17 y = train['Disbursed'] 18 ''' 19 1.不管任何參數,都用默認的,我們擬合下數據看看: 20 ''' 21 ''' 22 rf0 = RandomForestClassifier(oob_score=True, random_state=10) 23 rf0.fit(X,y) 24 print (rf0.oob_score_) 25 y_predprob = rf0.predict_proba(X)[:,1] 26 print( "AUC Score (Train): %f" % metrics.roc_auc_score(y, y_predprob)) 27 ''' 28 ''' 29 輸出如下,可見袋外分數已經很高,而且AUC分數也很高。 30 相對於GBDT的默認參數輸出,RF的默認參數擬合效果對本例要好一些。 31 0.98005 32 AUC Score (Train): 0.999833 33 ''' 34 ''' 35 2.我們首先對n_estimators進行網格搜索: 36 ''' 37 ''' 38 param_test1 = {'n_estimators':[10,20,30,40,50,60,70]} 39 gsearch1 = GridSearchCV(estimator = RandomForestClassifier(min_samples_split=100, 40 min_samples_leaf=20,max_depth=8,max_features='sqrt' ,random_state=10), 41 param_grid = param_test1, scoring='roc_auc',cv=5) 42 gsearch1.fit(X,y) 43 print(gsearch1.grid_scores_, gsearch1.best_params_, gsearch1.best_score_) 44 ''' 45 ''' 46 這樣我們得到了最佳的弱學習器迭代次數60, 47 3.接着我們對決策樹最大深度max_depth和內部節點再划分所需最小樣本數min_samples_split進行網格搜索。 48 ''' 49 ''' 50 param_test2 = {'max_depth':[3,5,7,9,11,13], 'min_samples_split':[50,70,90,110,130,150,170,190]} 51 gsearch2 = GridSearchCV(estimator = RandomForestClassifier(n_estimators= 60, 52 min_samples_leaf=20,max_features='sqrt' ,oob_score=True, random_state=10), 53 param_grid = param_test2, scoring='roc_auc',iid=False, cv=5) 54 gsearch2.fit(X,y) 55 print(gsearch2.grid_scores_, gsearch2.best_params_, gsearch2.best_score_) 56 ''' 57 ''' 58 得到最佳 max_depth = 13 59 我們看看我們現在模型的袋外分數: 60 ''' 61 ''' 62 rf1 = RandomForestClassifier(n_estimators= 60, max_depth=13, min_samples_split=110, 63 min_samples_leaf=20,max_features='sqrt' ,oob_score=True, random_state=10) 64 rf1.fit(X,y) 65 print( rf1.oob_score_) 66 y_predprob = rf1.predict_proba(X)[:,1] 67 print( "AUC Score (Train): %f" % metrics.roc_auc_score(y, y_predprob)) 68 ''' 69 ''' 70 輸出結果為0.984 71 相對於默認情況,袋外分數有提高,也就是說模型的泛化能力變好了 72 對於內部節點再划分所需最小樣本數min_samples_split,我們暫時不能一起定下來,因為這個還和決策樹其他的參數存在關聯。 73 4.下面我們再對內部節點再划分所需最小樣本數min_samples_split和葉子節點最少樣本數min_samples_leaf一起調參。 74 ''' 75 ''' 76 param_test3 = {'min_samples_split':[80,100,120,140], 'min_samples_leaf':[10,20,30,40,50]} 77 gsearch3 = GridSearchCV(estimator = RandomForestClassifier(n_estimators= 60, max_depth=13, 78 max_features='sqrt' ,oob_score=True, random_state=10), 79 param_grid = param_test3, scoring='roc_auc',iid=False, cv=5) 80 gsearch3.fit(X,y) 81 print(gsearch3.grid_scores_, gsearch3.best_params_, gsearch3.best_score_) 82 ''' 83 ''' 84 得到最佳'min_samples_leaf': 20, 'min_samples_split': 120 85 5.最后我們再對最大特征數max_features做調參: 86 ''' 87 ''' 88 param_test4 = {'max_features':[3,5,7,9,11]} 89 gsearch4 = GridSearchCV(estimator = RandomForestClassifier(n_estimators= 60, max_depth=13, min_samples_split=120, 90 min_samples_leaf=20 ,oob_score=True, random_state=10), 91 param_grid = param_test4, scoring='roc_auc',iid=False, cv=5) 92 gsearch4.fit(X,y) 93 print(gsearch4.grid_scores_, gsearch4.best_params_, gsearch4.best_score_) 94 ''' 95 ''' 96 得到'max_features': 7 97 6.用我們搜索到的最佳參數,我們再看看最終的模型擬合: 98 ''' 99 rf2 = RandomForestClassifier(n_estimators= 60, max_depth=13, min_samples_split=120, 100 min_samples_leaf=20,max_features=7 ,oob_score=True, random_state=10) 101 rf2.fit(X,y) 102 print (rf2.oob_score_) 103 ''' 104 此時的輸出為:0.984 105 可見此時模型的袋外分數基本沒有提高,主要原因是0.984已經是一個很高的袋外分數了, 106 如果想進一步需要提高模型的泛化能力,我們需要更多的數據。 107 '''