随机森林调参笔记

1. scikit-learn随机森林类库概述

    在scikit-learn中,RF的分类类是RandomForestClassifier,回归类是RandomForestRegressor。当然RF的变种Extra Trees也有, 分类类ExtraTreesClassifier,回归类ExtraTreesRegressor。由于RF和Extra Trees的区别较小,调参方法基本相同,本文只关注于RF的调参。

2.  RF框架参数

    1) n_estimators: 也就是弱学习器的最大迭代次数,或者说最大的弱学习器的个数。一般来说n_estimators太小,容易欠拟合,n_estimators太大,计算量会太大,并且n_estimators到一定的数量后,再增大n_estimators获得的模型提升会很小,所以一般选择一个适中的数值。默认是100。

    2) oob_score :即是否采用袋外样本来评估模型的好坏。默认识False。个人推荐设置为True,因为袋外分数反应了一个模型拟合后的泛化能力。

    3) criterion即CART树做划分时对特征的评价标准。分类模型和回归模型的损失函数是不一样的。分类RF对应的CART分类树默认是基尼系数gini,另一个可选择的标准是信息增益。回归RF对应的CART回归树默认是均方差mse,另一个可以选择的标准是绝对值差mae。一般来说选择默认的标准就已经很好的。

    从上面可以看出, RF重要的框架参数比较少,主要需要关注的是 n_estimators,即RF最大的决策树个数。

3.  RF决策树参数

    下面我们再来看RF的决策树参数,如下:

    1) RF划分时考虑的最大特征数max_features: 可以使用很多种类型的值,默认是"auto",意味着划分时最多考虑N−√N个特征;如果是"log2"意味着划分时最多考虑log2N个特征;如果是"sqrt"或者"auto"意味着划分时最多考虑N−√N个特征。如果是整数,代表考虑的特征绝对数。如果是浮点数,代表考虑特征百分比,即考虑(百分比xN)取整后的特征数。其中N为样本总特征数。一般我们用默认的"auto"就可以了,如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。

    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。

接下来以UCI数据集中的breast_cancer进行实验。

4.  引入必要包和数据

编译环境python3.6

import pandas as pd
from sklearn import metrics
import matplotlib.pylab as plt
from sklearn.grid_search import GridSearchCV
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.cross_validation import train_test_split

cancer=load_breast_cancer()
X=cancer.data
y=cancer.target

查看数据的类别分布:

def all_list(arr):
    result = {}
    for i in set(arr):
        result[i] = arr.count(i)
    return result
all_list(list(y))

结果如下:

{0: 212, 1: 357}

 可以看出0、1两类差别不是特别大。

5. 参数调优

rf0 = RandomForestClassifier(oob_score=True,n_estimators=20, random_state=33)
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))

输出如下,可见袋外分数已经很高,而且AUC分数也很高。

0.9420035149384886
AUC Score (Train): 0.999960

我们首先对n_estimators进行网格搜索:

param_test1 = {'n_estimators':list(range(10,81,10))}
gsearch1 = GridSearchCV(estimator = RandomForestClassifier(oob_score=True,random_state=33), 
                       param_grid = param_test1, scoring='roc_auc',cv=5,n_jobs=-1)
gsearch1.fit(X,y)
gsearch1.grid_scores_, gsearch1.best_params_, gsearch1.best_score_

 结果如下:

([mean: 0.98526, std: 0.01117, params: {'n_estimators': 10},
  mean: 0.98817, std: 0.00957, params: {'n_estimators': 20},
  mean: 0.99013, std: 0.00791, params: {'n_estimators': 30},
  mean: 0.99029, std: 0.00737, params: {'n_estimators': 40},
  mean: 0.99052, std: 0.00748, params: {'n_estimators': 50},
  mean: 0.99009, std: 0.00797, params: {'n_estimators': 60},
  mean: 0.99083, std: 0.00832, params: {'n_estimators': 70},
  mean: 0.99059, std: 0.00839, params: {'n_estimators': 80}],
 {'n_estimators': 70},
 0.9908258073986259)

当n_estimators=40时得分最高,也可以继续搜索50附近哪个取值得分最高,这里我们取n_estimators=40。

这样我们得到了最佳的弱学习器迭代次数,接着我们对决策树最大深度max_depth和内部节点再划分所需最小样本数min_samples_split进行网格搜索。

 param_test2 = {'max_depth':list(range(1,14,2)), 'min_samples_split':list(range(50,201,20))}
gsearch2 = GridSearchCV(estimator = RandomForestClassifier(n_estimators= 70, oob_score=True, random_state=33),
   param_grid = param_test2, scoring='roc_auc',iid=False, cv=5,n_jobs=-1)
gsearch2.fit(X,y)
gsearch2.grid_scores_, gsearch2.best_params_, gsearch2.best_score_

结果如下:

([mean: 0.98264, std: 0.01191, params: {'max_depth': 1, 'min_samples_split': 50},
  mean: 0.98264, std: 0.01191, params: {'max_depth': 1, 'min_samples_split': 70},
  mean: 0.98264, std: 0.01191, params: {'max_depth': 1, 'min_samples_split': 90},
  mean: 0.98264, std: 0.01191, params: {'max_depth': 1, 'min_samples_split': 110},
  mean: 0.98264, std: 0.01191, params: {'max_depth': 1, 'min_samples_split': 130},
  mean: 0.98264, std: 0.01191, params: {'max_depth': 1, 'min_samples_split': 150},
  mean: 0.98264, std: 0.01191, params: {'max_depth': 1, 'min_samples_split': 170},
  mean: 0.98264, std: 0.01191, params: {'max_depth': 1, 'min_samples_split': 190},
  mean: 0.98801, std: 0.00731, params: {'max_depth': 3, 'min_samples_split': 50},
  mean: 0.98754, std: 0.00737, params: {'max_depth': 3, 'min_samples_split': 70},
  mean: 0.98682, std: 0.00775, params: {'max_depth': 3, 'min_samples_split': 90},
  mean: 0.98638, std: 0.00859, params: {'max_depth': 3, 'min_samples_split': 110},
  mean: 0.98586, std: 0.00878, params: {'max_depth': 3, 'min_samples_split': 130},
  mean: 0.98559, std: 0.00885, params: {'max_depth': 3, 'min_samples_split': 150},
  mean: 0.98638, std: 0.00866, params: {'max_depth': 3, 'min_samples_split': 170},
  mean: 0.98580, std: 0.00991, params: {'max_depth': 3, 'min_samples_split': 190},
  mean: 0.98849, std: 0.00711, params: {'max_depth': 5, 'min_samples_split': 50},
  mean: 0.98803, std: 0.00728, params: {'max_depth': 5, 'min_samples_split': 70},
  mean: 0.98784, std: 0.00785, params: {'max_depth': 5, 'min_samples_split': 90},
  mean: 0.98615, std: 0.00854, params: {'max_depth': 5, 'min_samples_split': 110},
  mean: 0.98602, std: 0.00876, params: {'max_depth': 5, 'min_samples_split': 130},
  mean: 0.98575, std: 0.00863, params: {'max_depth': 5, 'min_samples_split': 150},
  mean: 0.98618, std: 0.00876, params: {'max_depth': 5, 'min_samples_split': 170},
  mean: 0.98587, std: 0.00981, params: {'max_depth': 5, 'min_samples_split': 190},
  mean: 0.98804, std: 0.00769, params: {'max_depth': 7, 'min_samples_split': 50},
  mean: 0.98797, std: 0.00781, params: {'max_depth': 7, 'min_samples_split': 70},
  mean: 0.98719, std: 0.00822, params: {'max_depth': 7, 'min_samples_split': 90},
  mean: 0.98596, std: 0.00876, params: {'max_depth': 7, 'min_samples_split': 110},
  mean: 0.98589, std: 0.00898, params: {'max_depth': 7, 'min_samples_split': 130},
  mean: 0.98524, std: 0.00921, params: {'max_depth': 7, 'min_samples_split': 150},
  mean: 0.98618, std: 0.00876, params: {'max_depth': 7, 'min_samples_split': 170},
  mean: 0.98587, std: 0.00981, params: {'max_depth': 7, 'min_samples_split': 190},
  mean: 0.98804, std: 0.00756, params: {'max_depth': 9, 'min_samples_split': 50},
  mean: 0.98797, std: 0.00772, params: {'max_depth': 9, 'min_samples_split': 70},
  mean: 0.98713, std: 0.00832, params: {'max_depth': 9, 'min_samples_split': 90},
  mean: 0.98596, std: 0.00876, params: {'max_depth': 9, 'min_samples_split': 110},
  mean: 0.98589, std: 0.00898, params: {'max_depth': 9, 'min_samples_split': 130},
  mean: 0.98524, std: 0.00921, params: {'max_depth': 9, 'min_samples_split': 150},
  mean: 0.98618, std: 0.00876, params: {'max_depth': 9, 'min_samples_split': 170},
  mean: 0.98587, std: 0.00981, params: {'max_depth': 9, 'min_samples_split': 190},
  mean: 0.98804, std: 0.00756, params: {'max_depth': 11, 'min_samples_split': 50},
  mean: 0.98797, std: 0.00772, params: {'max_depth': 11, 'min_samples_split': 70},
  mean: 0.98713, std: 0.00832, params: {'max_depth': 11, 'min_samples_split': 90},
  mean: 0.98596, std: 0.00876, params: {'max_depth': 11, 'min_samples_split': 110},
  mean: 0.98589, std: 0.00898, params: {'max_depth': 11, 'min_samples_split': 130},
  mean: 0.98524, std: 0.00921, params: {'max_depth': 11, 'min_samples_split': 150},
  mean: 0.98618, std: 0.00876, params: {'max_depth': 11, 'min_samples_split': 170},
  mean: 0.98587, std: 0.00981, params: {'max_depth': 11, 'min_samples_split': 190},
  mean: 0.98804, std: 0.00756, params: {'max_depth': 13, 'min_samples_split': 50},
  mean: 0.98797, std: 0.00772, params: {'max_depth': 13, 'min_samples_split': 70},
  mean: 0.98713, std: 0.00832, params: {'max_depth': 13, 'min_samples_split': 90},
  mean: 0.98596, std: 0.00876, params: {'max_depth': 13, 'min_samples_split': 110},
  mean: 0.98589, std: 0.00898, params: {'max_depth': 13, 'min_samples_split': 130},
  mean: 0.98524, std: 0.00921, params: {'max_depth': 13, 'min_samples_split': 150},
  mean: 0.98618, std: 0.00876, params: {'max_depth': 13, 'min_samples_split': 170},
  mean: 0.98587, std: 0.00981, params: {'max_depth': 13, 'min_samples_split': 190}],
 {'max_depth': 5, 'min_samples_split': 50},
 0.9884872542750041)

现在模型的袋外分数: 

 rf1 = RandomForestClassifier(n_estimators= 70, max_depth=5, min_samples_split=50,oob_score=True, random_state=33)
rf1.fit(X,y)
print(rf1.oob_score_)

0.9507908611599297

可见此时我们的袋外分数有一定的提高,也就是时候模型的泛化能力增强了。

对于内部节点再划分所需最小样本数min_samples_split,我们暂时不能一起定下来,因为这个还和决策树其他的参数存在关联。下面我们再对内部节点再划分所需最小样本数min_samples_split和叶子节点最少样本数min_samples_leaf一起调参。

param_test3 = {'min_samples_split':list(range(10,150,5)), 'min_samples_leaf':list(range(1,50,1))}
gsearch3 = GridSearchCV(estimator = RandomForestClassifier(n_estimators= 70, max_depth=5,oob_score=True, min_samples_split=50,random_state=33),
   param_grid = param_test3, scoring='roc_auc',iid=False, cv=5,n_jobs=-1)
gsearch3.fit(X,y)
gsearch3.grid_scores_, gsearch3.best_params_, gsearch3.best_score_

结果如下:(输出结果有点多,只截取了最后5条)

·····
  mean: 0.98608, std: 0.00906, params: {'min_samples_leaf': 36, 'min_samples_split': 85},
  mean: 0.98595, std: 0.00894, params: {'min_samples_leaf': 36, 'min_samples_split': 90},
  mean: 0.98602, std: 0.00895, params: {'min_samples_leaf': 36, 'min_samples_split': 95},
  mean: 0.98602, std: 0.00914, params: {'min_samples_leaf': 36, 'min_samples_split': 100},
  mean: 0.98589, std: 0.00916, params: {'min_samples_leaf': 36, 'min_samples_split': 105},
  ...],
 {'min_samples_leaf': 1, 'min_samples_split': 15},
 0.9913790234949749)

 最后我们再对最大特征数max_features做调参:

param_test4 = {'max_features':list(range(3,31,2))}
gsearch4 = GridSearchCV(estimator = RandomForestClassifier(n_estimators= 70, max_depth=5, min_samples_split=15,min_samples_leaf=1,oob_score=True, random_state=33),
   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.99060, std: 0.00678, params: {'max_features': 3},
  mean: 0.99138, std: 0.00587, params: {'max_features': 5},
  mean: 0.98927, std: 0.00710, params: {'max_features': 7},
  mean: 0.98825, std: 0.00789, params: {'max_features': 9},
  mean: 0.98929, std: 0.00815, params: {'max_features': 11},
  mean: 0.98814, std: 0.00837, params: {'max_features': 13},
  mean: 0.98951, std: 0.00782, params: {'max_features': 15},
  mean: 0.98673, std: 0.01030, params: {'max_features': 17},
  mean: 0.98805, std: 0.00909, params: {'max_features': 19},
  mean: 0.98711, std: 0.00938, params: {'max_features': 21},
  mean: 0.98843, std: 0.00766, params: {'max_features': 23},
  mean: 0.98884, std: 0.00820, params: {'max_features': 25},
  mean: 0.98644, std: 0.01039, params: {'max_features': 27},
  mean: 0.98886, std: 0.00754, params: {'max_features': 29}],
 {'max_features': 5},
 0.9913790234949749)

用我们搜索到的最佳参数,我们再看看最终的模型拟合:

rf1 = RandomForestClassifier(n_estimators= 70, max_depth=5, min_samples_split=15,min_samples_leaf=1,max_features=5,oob_score=True, random_state=33)
rf1.fit(X,y)
print(rf1.oob_score_)
y_predprob = rf1.predict_proba(X)[:,1]
print ("AUC Score (Train): %f" % metrics.roc_auc_score(y, y_predprob))

结果如下:

0.9560632688927944
AUC Score (Train): 0.998599

我们从结果可以看出,通过调参后袋外分数有很大提高,AUC得分小幅度降低。以上表明了,模型泛化能力增强,分类能力有降低,但幅度极小。总体来说,模型相比最初模型有些许提高。

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值