在 scikit-learn中, RandomForest 的分类类是RandomForestClassifier,回归类是RandomForestRegressor ,需要调参的参数包括两部分,第一部分是 Bagging框架的参数,第二部分是CART决策树的参数。
sklearn 官网地址( RandomForestClassifier ): http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html#sklearn.ensemble.RandomForestClassifier
classsklearn.ensemble.RandomForestClassifier (n_estimators=10, criterion='gini', max_depth=None,min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0,max_features='auto', max_leaf_nodes=None, min_impurity_split=1e-07,bootstrap=True, oob_score=False, n_jobs=1, random_state=None, verbose=0,warm_start=False, class_weight=None )
参数解读
Bagging框架的参数
和GBDT对比 , GBDT的框架参数比较多,重要的有最大迭代器个数,步长和子采样比例,调参起来比较费力。但是RF则比较简单,这是因为bagging框架里的各个弱学习器之间是没有依赖关系的,这减小的调参的难度。换句话说,达到同样的调参效果,RF调参时间要比GBDT少一些。 下面我来看看 RF重要的Bagging框架的参数,由于RandomForestClassifier 和 RandomForestRegressor参数绝大部分相同,这里会将它们一起讲,不同点会指出。
n_estimators: 也就是弱学习器的最大迭代次数,或者说 最大的弱学习器的个数 , 默认是 10 。一般来说n_estimators太小,容易欠拟合,n_estimators太大,又容易过拟合,一般选择一个适中的数值。 对 Random Forest 来说,增加“子模型数”( n_estimators )可以明显降低整体模型的方差,且不会对子模型的偏差和方差有任何影响。模型的准确度会随着“子模型数”的增加而提高,由于减少的是整体模型方差公式的第二项,故准确度的提高有一个上限。在实际应用中,可以以10为单位,考察取值范围在1至201的调参情况。
对比,Random Forest的子模型都拥有较低的偏差,整体模型的训练过程旨在降低方差,故其需要较少的子模型(n_estimators默认值为10)且子模型不为弱模型(max_depth的默认值为None);Gradient Tree Boosting的子模型都拥有较低的方差,整体模型的训练过程旨在降低偏差,故其需要较多的子模型(n_estimators默认值为100)且子模型为弱模型(max_depth的默认值为3)。 bootstrap :默认 True , 是否有放回的采样。 oob_score : 默认识False , 即是否采用袋外样本来评估模型的好坏。 有放回采样中大约 36.8%的没有被采样到的数据,我们常常称之为袋外数据(Out Of Bag, 简称OOB) , 这些数据没有参与训练集模型的拟合,因此可以用来检测模型的泛化能力。 个人推荐设置为True ,因为袋外分数反应了一个模型拟合后的泛化能力 。对 单个模型的参数训练,我们知道可以用cross validation(cv)来进行,但是特别消耗时间,而且对于随机森林这种情况也没有大的必要,所以就用这个数据对决策树模型进行验证,算是一个简单的交叉验证 , 性能消耗小,但是效果不错。 criterion : 即CART树做划分时对特征的评价标准 , 分类模型和回归模型的损失函数是不一样的。分类RF对应的CART分类树默认是 基尼系数gini ,另一个可选择的标准是 信息增益entropy ,是用 来选择节点 的最优特征和切分点的两个准则 。回归RF对应的CART回归树默认是 均方差mse ,另一个可以选择的标准是 绝对值差mae 。 一般来说选择默认的标准就已经很好的。
从上面可以看出, RF重要的框架参数比较少,主要需要关注的是 n_estimators,即RF最大的决策树个数。
RF 决策树的参数
RF 的决策树参数,它要调参的参数基本和 GBDT 相同,如下 :
max_features : RF 划分时考虑的最大特征数。可以使用很多种类型的值 ,默认是 "None" , 意味着划分时考虑所有的特征数 ;如果是 "log2" 意味着划分时最多考虑 log2N 个特征;如果是 "sqrt" 或者 "auto" 意味着划分时最多考虑 N −−√ N 个特征。如果是 整数 ,代表考虑的特征绝对数。如果是 浮点数 ,代表考虑特征百分比,即考虑(百分比 xN )取整后的特征数,其中 N 为样本总特征数。一般来说, 如果样本特征数不多,比如小于 50 ,我们用默认的 "None" 就可以了 , 如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间 。 max_depth : 决策树最大深度。默认为 "None" ,决策树在建立子树的时候 不会限制 子树的深度 这样建树时,会使每一个叶节点只有一个类别,或是达到min_samples_split 。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。 常用的可以取值 10-100 之间。 min_samples_split : 内部节点再划分所需最小样本数,默认 2 。这个值限制了子树继续划分的条件, 如果 某节点的样本数少于 min_samples_split ,则不会继续再尝试选择最优特征来进行划分 。 默认是 2 . 如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。 min_samples_leaf : 叶子节点最少样本数。 这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝 。 默认是 1 , 可以输入最少的样本数的整数,或者最少样本数占样本总数的百分比。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。 min_weight_fraction_leaf :叶子节点最小的样本权重和。 这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝 。 默认是 0 ,就是不考虑权重问题 。一般来说, 如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了 。 max_leaf_nodes : 最大叶子节点数。 通过限制最大叶子节点数,可以防止过拟合,默认是 "None” ,即不限制最大的叶子节点数 。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值, 但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。 min_impurity_split : 节点划分最小不纯度。这个值限制了决策树的增长, 如果某节点的不纯度 ( 基于基尼系数,均方差 ) 小于这个阈值,则该节点不再生成子节点 ,即为叶子节点 。 一般不推荐改动默认值 1e-7 。
上面决策树参数中最重要的包括最大特征数 max_features , 最大深度 max_depth , 内部节点再划分所需最小样本数 min_samples_split 和叶子节点最少样本数 min_samples_leaf 。
splitter: 随机选择属性 " random " 还是选择不纯度最大 " best " 的属性, 建议用默认 best 。 presort: 是否对数据进行预分类,以加快拟合中最佳分裂点的发现。 默认 False ,适用于大数据集。 小数据集使用 True, 可以加快训练。是否预排序,预排序可以加速查找最佳分裂点,对于稀疏数据不管用,Bool,auto:非稀疏数据则预排序,若稀疏数据则不预排序
进行预测的几种常用方法
predict_proba(x) :给出带有概率值的结果。每个点在 所有label (类别) 的概率和为1. predict(x) :直接给出预测结果。内部还是调用的predict_proba(),根据概率的结果看哪个类型的预测值最高就是哪个类型。 predict_log_proba(x) :和predict_proba基本上一样,只是把结果给做了log()处理。
RandomForest调参实例
import pandas as pd import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.grid_search import GridSearchCV from sklearn import cross_validation, metrics import matplotlib.pylab as plt %matplotlib inline train= pd.read_csv('C:\\Users\\86349\\Desktop\\train_modified\\train_modified.csv' ) target='Disbursed' IDcol= 'ID' train['Disbursed' ].value_counts() 0 19680 1 320 Name:Disbursed, dtype: int64 x_columns = [x for x in train.columns if x not in [target,IDcol]] X = train[x_columns] y = train['Disbursed' ] rf0 = RandomForestClassifier(oob_score=True , random_state= 10 ) rf0.fit(X,y) print rf0.oob_score_ y_predprob = rf0.predict_proba(X)[:,1 ] print "AUC Score (Train): %f" % metrics.roc_auc_score(y,y_predprob) param_test1= {'n_estimators' :range( 10 , 71 , 10 )} gsearch1= GridSearchCV(estimator = RandomForestClassifier(min_samples_split=100 , min_samples_leaf=20 ,max_depth= 8 ,max_features= 'sqrt' ,random_state= 10 ), param_grid =param_test1, scoring='roc_auc' ,cv= 5 ) gsearch1.fit(X,y) gsearch1.grid_scores_,gsearch1.best_params_, gsearch1.best_score_ ([mean:0.80681 , std: 0.02236 , params: { 'n_estimators' : 10 }, mean: 0.81600 , std: 0.03275 , params:{ 'n_estimators' : 20 }, mean: 0.81818 , std: 0.03136 , params:{ 'n_estimators' : 30 }, mean: 0.81838 , std: 0.03118 , params:{ 'n_estimators' : 40 }, mean: 0.82034 , std: 0.03001 , params:{ 'n_estimators' : 50 }, mean: 0.82113 , std: 0.02966 , params:{ 'n_estimators' : 60 }, mean: 0.81992 , std: 0.02836 , params:{ 'n_estimators' : 70 }], {'n_estimators' : 60 }, 0.8211334476626017 ) param_test2= {'max_depth' :range( 3 , 14 , 2 ), 'min_samples_split' :range( 50 , 201 , 20 )} gsearch2= GridSearchCV(estimator = RandomForestClassifier(n_estimators= 60 , min_samples_leaf=20 ,max_features= 'sqrt' ,oob_score= True ,random_state= 10 ), param_grid = param_test2,scoring='roc_auc' ,iid= False , cv= 5 ) gsearch2.fit(X,y) gsearch2.grid_scores_,gsearch2.best_params_, gsearch2.best_score_ ([mean:0.79379 , std: 0.02347 , params: { 'min_samples_split' : 50 , 'max_depth' : 3 }, mean: 0.79339 , std: 0.02410 , params:{ 'min_samples_split' : 70 , 'max_depth' : 3 }, mean: 0.79350 , std: 0.02462 , params:{ 'min_samples_split' : 90 , 'max_depth' : 3 }, mean: 0.79367 , std: 0.02493 , params:{ 'min_samples_split' : 110 , 'max_depth' : 3 }, mean: 0.79387 , std: 0.02521 , params:{ 'min_samples_split' : 130 , 'max_depth' : 3 }, mean: 0.79373 , std: 0.02524 , params:{ 'min_samples_split' : 150 , 'max_depth' : 3 }, mean: 0.79378 , std: 0.02532 , params:{ 'min_samples_split' : 170 , 'max_depth' : 3 }, mean: 0.79349 , std: 0.02542 , params:{ 'min_samples_split' : 190 , 'max_depth' : 3 }, mean: 0.80960 , std: 0.02602 , params:{ 'min_samples_split' : 50 , 'max_depth' : 5 }, mean: 0.80920 , std: 0.02629 , params:{ 'min_samples_split' : 70 , 'max_depth' : 5 }, mean: 0.80888 , std: 0.02522 , params:{ 'min_samples_split' : 90 , 'max_depth' : 5 }, mean: 0.80923 , std: 0.02777 , params:{ 'min_samples_split' : 110 , 'max_depth' : 5 }, mean: 0.80823 , std: 0.02634 , params:{ 'min_samples_split' : 130 , 'max_depth' : 5 }, mean: 0.80801 , std: 0.02637 , params:{ 'min_samples_split' : 150 , 'max_depth' : 5 }, mean: 0.80792 , std: 0.02685 , params:{ 'min_samples_split' : 170 , 'max_depth' : 5 }, mean: 0.80771 , std: 0.02587 , params:{ 'min_samples_split' : 190 , 'max_depth' : 5 }, mean: 0.81688 , std: 0.02996 , params:{ 'min_samples_split' : 50 , 'max_depth' : 7 }, mean: 0.81872 , std: 0.02584 , params:{ 'min_samples_split' : 70 , 'max_depth' : 7 }, mean: 0.81501 , std: 0.02857 , params:{ 'min_samples_split' : 90 , 'max_depth' : 7 }, mean: 0.81476 , std: 0.02552 , params:{ 'min_samples_split' : 110 , 'max_depth' : 7 }, mean: 0.81557 , std: 0.02791 , params:{ 'min_samples_split' : 130 , 'max_depth' : 7 }, mean: 0.81459 , std: 0.02905 , params:{ 'min_samples_split' : 150 , 'max_depth' : 7 }, mean: 0.81601 , std: 0.02808 , params:{ 'min_samples_split' : 170 , 'max_depth' : 7 }, mean: 0.81704 , std: 0.02757 , params:{ 'min_samples_split' : 190 , 'max_depth' : 7 }, mean: 0.82090 , std: 0.02665 , params:{ 'min_samples_split' : 50 , 'max_depth' : 9 }, mean: 0.81908 , std: 0.02527 , params:{ 'min_samples_split' : 70 , 'max_depth' : 9 }, mean: 0.82036 , std: 0.02422 , params:{ 'min_samples_split' : 90 , 'max_depth' : 9 }, mean: 0.81889 , std: 0.02927 , params:{ 'min_samples_split' : 110 , 'max_depth' : 9 }, mean: 0.81991 , std: 0.02868 , params:{ 'min_samples_split' : 130 , 'max_depth' : 9 }, mean: 0.81788 , std: 0.02436 , params:{ 'min_samples_split' : 150 , 'max_depth' : 9 }, mean: 0.81898 , std: 0.02588 , params:{ 'min_samples_split' : 170 , 'max_depth' : 9 }, mean: 0.81746 , std: 0.02716 , params:{ 'min_samples_split' : 190 , 'max_depth' : 9 }, mean: 0.82395 , std: 0.02454 , params:{ 'min_samples_split' : 50 , 'max_depth' : 11 }, mean: 0.82380 , std: 0.02258 , params:{ 'min_samples_split' : 70 , 'max_depth' : 11 }, mean: 0.81953 , std: 0.02552 , params:{ 'min_samples_split' : 90 , 'max_depth' : 11 }, mean: 0.82254 , std: 0.02366 , params:{ 'min_samples_split' : 110 , 'max_depth' : 11 }, mean: 0.81950 , std: 0.02768 , params:{ 'min_samples_split' : 130 , 'max_depth' : 11 }, mean: 0.81887 , std: 0.02636 , params:{ 'min_samples_split' : 150 , 'max_depth' : 11 }, mean: 0.81910 , std: 0.02734 , params:{ 'min_samples_split' : 170 , 'max_depth' : 11 }, mean: 0.81564 , std: 0.02622 , params:{ 'min_samples_split' : 190 , 'max_depth' : 11 }, mean: 0.82291 , std: 0.02092 , params:{ 'min_samples_split' : 50 , 'max_depth' : 13 }, mean: 0.82177 , std: 0.02513 , params:{ 'min_samples_split' : 70 , 'max_depth' : 13 }, mean: 0.82415 , std: 0.02480 , params:{ 'min_samples_split' : 90 , 'max_depth' : 13 }, mean: 0.82420 , std: 0.02417 , params:{ 'min_samples_split' : 110 , 'max_depth' : 13 }, mean: 0.82209 , std: 0.02481 , params:{ 'min_samples_split' : 130 , 'max_depth' : 13 }, mean: 0.81852 , std: 0.02227 , params:{ 'min_samples_split' : 150 , 'max_depth' : 13 }, mean: 0.81955 , std: 0.02885 , params:{ 'min_samples_split' : 170 , 'max_depth' : 13 }, mean: 0.82092 , std: 0.02600 , params:{ 'min_samples_split' : 190 , 'max_depth' : 13 }], {'max_depth' : 13 , 'min_samples_split' : 110 }, 0.8242016800050813 ) rf1= RandomForestClassifier(n_estimators= 60 , max_depth= 13 , min_samples_split= 110 , min_samples_leaf=20 ,max_features= 'sqrt' ,oob_score= True ,random_state= 10 ) rf1.fit(X,y) printrf1.oob_score_ param_test3= {'min_samples_split' :range( 80 , 150 , 20 ), 'min_samples_leaf' :range( 10 , 60 , 10 )} gsearch3= GridSearchCV(estimator = RandomForestClassifier(n_estimators= 60 ,max_depth= 13 , max_features='sqrt' ,oob_score= True , random_state= 10 ), param_grid = param_test3,scoring='roc_auc' ,iid= False , cv= 5 ) gsearch3.fit(X,y) gsearch3.grid_scores_,gsearch2.best_params_, gsearch2.best_score_ ([mean:0.82093 , std: 0.02287 , params: { 'min_samples_split' : 80 , 'min_samples_leaf' : 10 }, mean: 0.81913 , std: 0.02141 , params:{ 'min_samples_split' : 100 , 'min_samples_leaf' : 10 }, mean: 0.82048 , std: 0.02328 , params:{ 'min_samples_split' : 120 , 'min_samples_leaf' : 10 }, mean: 0.81798 , std: 0.02099 , params:{ 'min_samples_split' : 140 , 'min_samples_leaf' : 10 }, mean: 0.82094 , std: 0.02535 , params:{ 'min_samples_split' : 80 , 'min_samples_leaf' : 20 }, mean: 0.82097 , std: 0.02327 , params:{ 'min_samples_split' : 100 , 'min_samples_leaf' : 20 }, mean: 0.82487 , std: 0.02110 , params:{ 'min_samples_split' : 120 , 'min_samples_leaf' : 20 }, mean: 0.82169 , std: 0.02406 , params:{ 'min_samples_split' : 140 , 'min_samples_leaf' : 20 }, mean: 0.82352 , std: 0.02271 , params:{ 'min_samples_split' : 80 , 'min_samples_leaf' : 30 }, mean: 0.82164 , std: 0.02381 , params:{ 'min_samples_split' : 100 , 'min_samples_leaf' : 30 }, mean: 0.82070 , std: 0.02528 , params:{ 'min_samples_split' : 120 , 'min_samples_leaf' : 30 }, mean: 0.82141 , std: 0.02508 , params:{ 'min_samples_split' : 140 , 'min_samples_leaf' : 30 }, mean: 0.82278 , std: 0.02294 , params:{ 'min_samples_split' : 80 , 'min_samples_leaf' : 40 }, mean: 0.82141 , std: 0.02547 , params:{ 'min_samples_split' : 100 , 'min_samples_leaf' : 40 }, mean: 0.82043 , std: 0.02724 , params:{ 'min_samples_split' : 120 , 'min_samples_leaf' : 40 }, mean: 0.82162 , std: 0.02348 , params:{ 'min_samples_split' : 140 , 'min_samples_leaf' : 40 }, mean: 0.82225 , std: 0.02431 , params:{ 'min_samples_split' : 80 , 'min_samples_leaf' : 50 }, mean: 0.82225 , std: 0.02431 , params:{ 'min_samples_split' : 100 , 'min_samples_leaf' : 50 }, mean: 0.81890 , std: 0.02458 , params:{ 'min_samples_split' : 120 , 'min_samples_leaf' : 50 }, mean: 0.81917 , std: 0.02528 , params:{ 'min_samples_split' : 140 , 'min_samples_leaf' : 50 }], {'min_samples_leaf' : 20 , 'min_samples_split' : 120 }, 0.8248650279471544 ) param_test4= {'max_features' :range( 3 , 11 , 2 )} gsearch4= GridSearchCV(estimator = RandomForestClassifier(n_estimators= 60 ,max_depth= 13 , min_samples_split= 120 , min_samples_leaf=20 ,oob_score= True , random_state= 10 ), param_grid = param_test4,scoring='roc_auc' ,iid= False , cv= 5 ) gsearch4.fit(X,y) gsearch4.grid_scores_,gsearch4.best_params_, gsearch4.best_score_ ([mean:0.81981 , std: 0.02586 , params: { 'max_features' : 3 }, mean: 0.81639 , std: 0.02533 , params:{ 'max_features' : 5 }, mean: 0.82487 , std: 0.02110 , params:{ 'max_features' : 7 }, mean: 0.81704 , std: 0.02209 , params:{ 'max_features' : 9 }], {'max_features' : 7 }, 0.8248650279471544 ) rf2= RandomForestClassifier(n_estimators= 60 , max_depth= 13 , min_samples_split= 120 , min_samples_leaf=20 ,max_features= 7 ,oob_score= True , random_state= 10 ) rf2.fit(X,y) printrf2.oob_score_