天天看点

sklearn 随机森林_机器学习sklearn之随机森林(第三部分:随机森林在乳腺癌数据上的调参过程)下...

sklearn 随机森林_机器学习sklearn之随机森林(第三部分:随机森林在乳腺癌数据上的调参过程)下...

本文是机器学习sklearn系列笔记关于随机森林的调参:

飘哥:机器学习sklearn之随机森林​zhuanlan.zhihu.com

sklearn 随机森林_机器学习sklearn之随机森林(第三部分:随机森林在乳腺癌数据上的调参过程)下...

飘哥:机器学习sklearn之随机森林(第二部分:随机森林的调参)​zhuanlan.zhihu.com

sklearn 随机森林_机器学习sklearn之随机森林(第三部分:随机森林在乳腺癌数据上的调参过程)下...

飘哥:机器学习sklearn之随机森林(第三部分:随机森林在乳腺癌数据上的调参过程)上​zhuanlan.zhihu.com

sklearn 随机森林_机器学习sklearn之随机森林(第三部分:随机森林在乳腺癌数据上的调参过程)下...

F. 书写网格搜索的参数

为网格搜索做准备。首先为网格搜索选择参数,

有一些参数是没有参照的,没有最大值没有最小值,很难说清一个范围,这种情况下我们使用学习曲线,看趋势,就像前面我们对n_estimators做的,,现在大范围从头到尾跑一遍,然后在你跑出来的最优解中局部的跑一遍,我们一般不知道'n_estimators,max_depth,max_leaf_nodes到底是多少,除非自己把图画出来自己慢慢的数,我也知道最大叶子是数多少合适,怎么办,花学习曲线,然后再跑一个更小的区间。

param_grid = {'n_estimators':np.arange(0, 200, 10)}

param_grid = {'max_depth':np.arange(1, 20, 1)}

param_grid = {'max_leaf_nodes':np.arange(25,50,1)}

#对于大型数据集,可以尝试从1000来构建,先输入1000,每100个叶子一个区间,再逐渐缩小范围

有一些参数是可以找到一个范围的,或者说我们知道他们的取值和随着他们的取值,模型的整体准确率会如何变化,曲线是如何,这样的参数我们就可以直接跑网格搜索

param_grid = {'criterion':['gini', 'entropy']} #我们知道criterion就有两个值,一个是基尼系数和信息熵,就直接放进去让它跑。

param_grid = {'min_samples_split':np.arange(2, 2+20, 1)} #我们知道min_samples_split最小值是2,根据你数据的尺寸size,知道数据量里面叶子不可能太大,在它最小的基础上加上20,大的话加个50,加上一个我们看起来合理的范围。

param_grid = {'min_samples_leaf':np.arange(1, 1+10, 1)}

param_grid = {'max_features':np.arange(5,30,1)}

G. 调整max_depth

在前面已经介绍过了,调参选择的顺序,对模型影响越大的参数越先调整,前面说过除了n_estimators之外,对模型影响最大的是max_depth ,所以上来就调整max_depth

#调整max_depth

param_grid = {'max_depth':np.arange(1, 20, 1)}

# 一般根据数据的大小来进行一个试探,乳腺癌数据很小,所以可以采用1~10,或者1~20这样的试探

# 但对于像digit recognition那样的大型数据来说,我们应该尝试30~50层深度(或许还不足够)

# 更应该画出学习曲线,来观察深度对模型的影响

rfc = RandomForestClassifier(n_estimators=39

,random_state=90

)

GS = GridSearchCV(rfc,param_grid,cv=10)

GS.fit(data.data,data.target)

print(GS.best_params_)

print(GS.best_score_)

(用网格搜索的调参顺序其实也是一样的,第1步我们将它实例化,然后我们导入网格搜索GridSearchCV,里面输入传入实例化好的模型,输入调整的参数,输入交叉验证数值10个,param_grid参数,我们一般会放在括号外面来提前设置(param_grid = {'max_depth':np.arange(1, 20, 1)}),一般是一个字典,字典的键是我们要求的参数,值是我们给出的参数的范围。

运行上面代码,调参需要一点时间。)

输出结果:

{'max_depth': 11}

0.9718804920913884

我们看到上面的结果已经调整出来了一个模型,运行结果告诉我说,最好的深度是11,并且得到最好的分数是0.9718804920913884,这时候大家可能要疑惑了,还没有前面运行的结果高。前面没有调整最大深度的值是0.9719568317345088,怎么把深度加上了,反而准确率到下降了。

在这里,我们注意到,将max_depth设置为有限之后,模型的准确率下降了。限制max_depth,是让模型变得简单,把模型向左推(大家可以参考前面文章的图形,https://zhuanlan.zhihu.com/p/59184748,文章中泛化误差和模型关系复杂度关系图),而模型整体的准确率下降了,即整体的泛化误差上升了,这说明模型现在位于图像左边,即泛化误差最低点的左边(偏差为主导的一边)。通常来说,随机森林应该在泛化误差最低点的右边,树模型应该倾向于过拟合,而不是拟合不足。这和数据集本身有关,但也有可能是我们调整的n_estimators对于数据集来说太大,因此将模型拉到泛化误差最低点去了。然而,既然我们追求最低泛化误差,那我们就保留这个n_estimators,除非有其他的因素,可以帮助我们达到更高的准确率。

当模型位于图像左边时,我们需要的是增加模型复杂度(增加方差,减少偏差)的选项,因此max_depth应该尽量大,min_samples_leaf和min_samples_split都应该尽量小。这几乎是在说明,除了max_features(可以让模型先左,也可以让模型向右),我们没有任何参数可以调整了,因为max_depth,min_samples_leaf和min_samples_split是剪枝参数,是减小复杂度的参数。在这里,我们可以预言,我们已经非常接近模型的上限,模型很可能没有办法再进步了。

那我们这就来调整一下max_features,看看模型如何变化。

H. 调整max_features

max_features是唯一一个即能够将模型往左(低方差高偏差)推,也能够将模型往右(高方差低偏差)推的参数。我们需要根据调参前,模型所在的位置(在泛化误差最低点的左边还是右边)来决定我们要将max_features往哪边调。现在模型位于图像左侧,我们需要的是更高的复杂度,所以我们把max_features往更大的方向调整,可用的特征越多,模型才会越复杂,模型才会向右移动,max_features的默认最小值是sqrt(n_features),因此我们使用这个值作为调参范围的最小值。我们设置30,开平方应该比5高一些,那我门就用5做最小值。在5到30里面取出一个看那个max_features是最好的。

#调整max_features

param_grid = {'max_features':np.arange(5,30,1)}

rfc = RandomForestClassifier(n_estimators=39

,random_state=90

)

GS = GridSearchCV(rfc,param_grid,cv=10)

GS.fit(data.data,data.target)

print(GS.best_params_)

print(GS.best_score_)

输出结果:

{'max_features': 5}

0.9718804920913884

运行结果显示max_features,5是最好,从结果看是选择了下限,还告诉我们最佳分数是0.9718804920913884,发现什么?准确率又下降了。还是没有什么都么有调整的数值高。

这说明了网格搜索max_features升高之后,模型的准确率也降低了。这说明max_features升高后,我们把模型往右推,模型的泛化误差增加了。前面用max_depth往左推,泛化误差增加,现在用max_features往右推,泛化误差也增加,这说明模型本身已经处于泛化误差最低点,就是达到了泛化误差和模型复杂度关系图中的u型曲线的最低点,也就是不管你左推还是右推,泛化误差都增加,我们已经不需要调整任何参数了,已经达到了模型的预测上限,没有参数可以左右的部分了。剩下的那些误差,是噪声决定的,已经没有方差和偏差的舞台了。

如果到现实中,到这一步就可以结束了,因为模型复杂度和泛化误差已经告诉我们,模型不能在进步了,无论你怎么调整,他不能比97.19%更高了。调参和训练模型都需要很长的时间,明知道模型不能进步了还继续调整,这是一个没有效率的做法。如果我们希望模型更进一步,可以选择更换算法,或者更换做数据预处理的方式。在本文中,出于学习和探索的目的,我们继续调整参数,让大家观察一下模型的变化,看看我们预测得是否正确。

依然按照参数对模型整体准确率的影响程度进行调参。

I. 调整min_samples_leaf

从上面结果看,不管怎么调整min_samples_leaf其实是没有用的,我们只是为了看看效果。

需要说明的是对于min_samples_split和min_samples_leaf,一般是从他们的最小值开始向上增加10或20,面对高维度高样本量数据,如果不放心,也可以直接+50,对于大型数据,可能需要200~300的范围,主要是看你数据的尺寸,如果调整的时候发现准确率无论如何都上不来,那可以放心大胆调一个很大的数据,大力限制模型的复杂度,仅仅是运行速度比较慢,如果不好,大不了改回来,没什么问题。

#调整min_samples_leaf

param_grid={'min_samples_leaf':np.arange(1, 1+10, 1)}

rfc = RandomForestClassifier(n_estimators=39

,random_state=90

)

GS = GridSearchCV(rfc,param_grid,cv=10)

GS.fit(data.data,data.target)

print(GS.best_params_)

print(GS.best_score_)

输出结果

{'min_samples_leaf': 1}

0.9718804920913884

我们min_samples_leaf看到最佳参数是1,是我们极限最小值了,告诉我们你不能在增大了,你不能再把图像往左推了,它要变小了。best_score_是0.9718804920913884,发现这个数据一点都没有变过,因为模型本身已经到了最优值了。

调整min_samples_leaf的脚本中网格搜索返回了min_samples_leaf的最小值,并且模型整体的准确率还降低了,这和max_depth的情况一致,参数把模型向左推,但是模型的泛化误差上升了。在这种情况下,我们显然是不要把这个参数设置起来的,就让它默认就好了。

J. 调整min_samples_split

不懈努力,继续尝试min_samples_split

#调整min_samples_split

param_grid={'min_samples_split':np.arange(2, 2+20, 1)}

rfc = RandomForestClassifier(n_estimators=39

,random_state=90

)

GS = GridSearchCV(rfc,param_grid,cv=10)

GS.fit(data.data,data.target)

print(GS.best_params_)

print(GS.best_score_)

结果说明和min_samples_leaf一样的结果,返回最小值并且模型整体的准确率降低了。

K. 调整criterion

最后尝试一下criterion

#调整Criterion

param_grid = {'criterion':['gini', 'entropy']}

rfc = RandomForestClassifier(n_estimators=39

,random_state=90

)

GS = GridSearchCV(rfc,param_grid,cv=10)

GS.fit(data.data,data.target)

print(GS.best_params_)

print(GS.best_score_)

调整criterion与前结果一样。

说明:在前面调整max_depth,我们大家已经有感觉了,可能就是模型的极限了,因为随机森林应该是在泛化误差和模型复杂度关系图中是处于右边的,把图像往左边推,值还增加了,这个已经很可能是我的泛化误差的最小值了,大家可以把前面的代码都运行一遍,自己体验下差别。

L. 总结最佳参数

调整完毕,总结出模型的最佳参数

rfc = RandomForestClassifier(n_estimators=39,random_state=90)

score = cross_val_score(rfc,data.data,data.target,cv=10).mean()

print(score)

print(score - score_pre)

输出结果:

0.971956831745088

0.005264238181661218

看到上面的结果,会有些惊讶,做了这么多工作,才提升了0.005,大家要知道在实际工作中,调参获得的提升比这个值更小,如0.001,这是因为参数的影响对结果是说不清楚的,虽然提升的0.001,0.002,但是会让你的模型成为竞赛或者工作中最佳的模型,因为大家差的就是这0.1%,由于我们选择数据集比较特殊,调整max_depth完,就已经是最优结了。在整个调参过程之中,我们首先调整了n_estimators(无论如何都请先走这一步),然后调整max_depth,通过max_depth产生的结果,来判断模型位于复杂度-泛化误差图像的哪一边,从而选择我们应该调整的参数和调参的方向。如果感到困惑,也可以画很多学习曲线来观察参数会如何影响我们的准确率,选取学习曲线中单调的部分来放大研究(如同我们对n_estimators做的)。学习曲线的拐点也许就是我们一直在追求的,最佳复杂度对应的泛化误差最低点(也是方差和偏差的平衡点)。网格搜索也可以一起调整多个参数,大家只要有时间,可以自己跑一下,看看网格搜索会给我们怎样的结果,有时候,它的结果比我们的好,有时候,我们手动调整的结果会比较好。当然了,我们的乳腺癌数据集非常完美,所以只需要调n_estimators一个参数就达到了随机森林在这个数据集上表现得极限。在我使用的泰坦尼克号案例的数据中,使用同样的方法调出了如下的参数组合。

rfc = RandomForestClassifier(n_estimators=68

,random_state=90

,criterion="gini"

,min_samples_split=8

,min_samples_leaf=1

,max_depth=12

,max_features=2

,max_leaf_nodes=36

)

基于泰坦尼克号数据调整出来的参数,这个组合的准确率达到了83.915%,比单棵决策树提升了大约7%,比调参前的随机森林提升了2.02%,这对于调参来说其实是一个非常巨大的进步。不过,泰坦尼克号数据的运行缓慢,大家量力量时间而行,可以试试看用复杂度-泛化误差方法(方差-偏差方法)来解读一下这个调参结果和过程。