这篇文章中,使用基于方差和误差的调参方法,在乳腺癌数据上进行一次随机森林的调参。乳腺癌数据是sklearn自带的分类数据之一。node
案例中,每每使用真实数据,为何咱们要使用sklearn自带的数据呢?由于真实数据在随机森林下的调参过程,每每很是缓慢。真实数据量大,维度高,在使用随机森林以前须要一系列的处理,所以不太适合用来作直播中的案例演示。本来,我为你们准备了kaggle上下载的辨别手写数字的数据,有4W多条记录700多个左右的特征,随机森林在这个辨别手写数字的数据上有很是好的表现,其调参案例也是很是经典,可是因为数据的维度过高,太过复杂,运行一次完整的网格搜索须要四五个小时,所以不太可能拿来给你们进行演示。经典的泰坦尼克号数据,用来调参的话也是须要很长时间,所以我才选择sklearn当中自带的,结构相对清晰简单的数据来为你们作这个案例。你们感兴趣的话,能够进公众号(CDA微课学院)去下载数据,也能够直接到kaggle上进行下载,数据集名称是Digit Recognizer(https://www.kaggle.com/c/digi...)。python
那咱们接下来,就用乳腺癌数据,来看看咱们的调参代码。git
from sklearn.datasets import load_breast_cancer from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import GridSearchCV from sklearn.model_selection import cross_val_score import matplotlib.pyplot as plt import pandas as pd import numpy as np
data = load_breast_cancer() data data.data.shape data.target
能够看到,乳腺癌数据集有569条记录,30个特征,单看维度虽然不算过高,可是样本量很是少。过拟合的状况可能存在。算法
进行一次简单的建模,看看模型自己在数据集上的效果数组
rfc = RandomForestClassifier(n_estimators=100,random_state=90) score_pre = cross_val_score(rfc,data.data,data.target,cv=10).mean() score_pre
这里能够看到,随机森林在乳腺癌数据上的表现本就还不错,在现实数据集上,基本上不可能什么都不调就看到95%以上的准确率。app
在这里咱们选择学习曲线,可使用网格搜索吗?能够,可是只有学习曲线,才能看见趋势
我我的的倾向是,要看见n_estimators在什么取值开始变得平稳,是否一直推进模型总体准确率的上升等信息
第一次的学习曲线,能够先用来帮助咱们划定范围,咱们取每十个数做为一个阶段,来观察n_estimators的变化如何引发模型总体准确率的变化dom
#####【TIME WARNING: 30 seconds】##### scorel = [] for i in range(0,200,10): rfc = RandomForestClassifier(n_estimators=i+1, n_jobs=-1, random_state=90) score = cross_val_score(rfc,data.data,data.target,cv=10).mean() scorel.append(score) print(max(scorel),(scorel.index(max(scorel))*10)+1) plt.figure(figsize=[20,5]) plt.plot(range(1,201,10),scorel) plt.show() #list.index([object]),返回这个object在列表list中的索引
从运行结果来看,当n_estimators=41的时候score取得最大值0.968。学习
在肯定好的范围内,进一步细化学习曲线spa
scorel = [] for i in range(35,45): rfc = RandomForestClassifier(n_estimators=i, n_jobs=-1, random_state=90) score = cross_val_score(rfc,data.data,data.target,cv=10).mean() scorel.append(score) print(max(scorel),([*range(35,45)][scorel.index(max(scorel))])) plt.figure(figsize=[20,5]) plt.plot(range(35,45),scorel) plt.show()
调整n_estimators的效果显著,模型的准确率马上上升了0.005。接下来就进入网格搜索,咱们将使用网格搜索对参数一个个进行调整。为何咱们不一样时调整多个参数呢?缘由有两个:1)同时调整多个参数会运行很是缓慢,在课堂上咱们没有这么多的时间。2)同时调整多个参数,会让咱们没法理解参数的组合是怎么得来的,因此即使网格搜索调出来的结果很差,咱们也不知道从哪里去改。在这里,为了使用复杂度-泛化偏差方法(方差-误差方法),咱们对参数进行一个个地调整。rest
书写网格搜索的参数,为网格搜索作准备。
有一些参数是没有参照的,很难说清一个范围,这种状况下咱们使用学习曲线,看趋势
从曲线跑出的结果中选取一个更小的区间,再跑曲线
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']} param_grid = {'min_samples_split':np.arange(2, 2+20, 1)} param_grid = {'min_samples_leaf':np.arange(1, 1+10, 1)} param_grid = {'max_features':np.arange(5,30,1)}
开始按照参数对模型总体准确率的影响程度进行调参,首先调整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) GS.best_params_ GS.best_score_
在这里,咱们注意到,将max_depth设置为有限以后,模型的准确率降低了。限制max_depth,是让模型变得简单,把模型向左推,而模型总体的准确率降低了,即总体的泛化偏差上升了,这说明模型如今位于图像左边,即泛化偏差最低点的左边(误差为主导的一边)。一般来讲,随机森林应该在泛化偏差最低点的右边,树模型应该倾向于过拟合,而不是拟合不足。这和数据集自己有关,但也有多是咱们调整的n_estimators对于数据集来讲太大,所以将模型拉到泛化偏差最低点去了。然而,既然咱们追求最低泛化偏差,那咱们就保留这个n_estimators,除非有其余的因素,能够帮助咱们达到更高的准确率。
当模型位于图像左边时,咱们须要的是增长模型复杂度(增长方差,减小误差)的选项,所以max_depth应该尽可能大,min_samples_leaf和min_samples_split都应该尽可能小。这几乎是在说明,除了max_features,咱们没有任何参数能够调整了,由于max_depth,min_samples_leaf和min_samples_split是剪枝参数,是减少复杂度的参数。在这里,咱们能够预言,咱们已经很是接近模型的上限,模型极可能没有办法再进步了。
那咱们这就来调整一下max_features,看看模型如何变化。
max_features是惟一一个即可以将模型往左(低方差高误差)推,也可以将模型往右(高方差低误差)推的参数。咱们须要根据调参前,模型所在的位置(在泛化偏差最低点的左边仍是右边)来决定咱们要将max_features往哪边调。如今模型位于图像左侧,咱们须要的是更高的复杂度,所以咱们应该把max_features往更大的方向调整,可用的特征越多,模型才会越复杂。max_features的默认最小值是sqrt(n_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) GS.best_params_ GS.best_score_
网格搜索返回了max_features的最小值,可见max_features升高以后,模型的准确率下降了。这说明,咱们把模型往右推,模型的泛化偏差增长了。前面用max_depth往左推,如今用max_features往右推,泛化偏差都增长,这说明模型自己已经处于泛化偏差最低点,已经达到了模型的预测上限,没有参数能够左右的部分了。剩下的那些偏差,是噪声决定的,已经没有方差和误差的舞台了。
若是是现实案例,咱们到这一步其实就能够停下了,由于复杂度和泛化偏差的关系已经告诉咱们,模型不能再进步了。调参和训练模型都须要很长的时间,明知道模型不能进步了还继续调整,不是一个有效率的作法。若是咱们但愿模型更进一步,咱们会选择更换算法,或者更换作数据预处理的方式。可是在课上,出于练习和探索的目的,咱们继续调整咱们的参数,让你们观察一下模型的变化,看看咱们预测得是否正确。
依然按照参数对模型总体准确率的影响程度进行调参。
对于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) GS.best_params_ GS.best_score_
能够看见,网格搜索返回了min_samples_leaf的最小值,而且模型总体的准确率还下降了,这和max_depth的状况一致,参数把模型向左推,可是模型的泛化偏差上升了。在这种状况下,咱们显然是不要把这个参数设置起来的,就让它默认就行了。
不懈努力,继续尝试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) GS.best_params_ GS.best_score_
和min_samples_leaf同样的结果,返回最小值而且模型总体的准确率下降了。
最后尝试一下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) GS.best_params_ GS.best_score_
调整完毕,总结出模型的最佳参数
rfc = RandomForestClassifier(n_estimators=39,random_state=90) score = cross_val_score(rfc,data.data,data.target,cv=10).mean() score score - score_pre
在整个调参过程之中,咱们首先调整了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%,这对于调参来讲实际上是一个很是巨大的进步。不过,泰坦尼克号数据的运行缓慢,你们量力量时间而行,能够试试看用复杂度-泛化偏差方法(方差-误差方法)来解读一下这个调参结果和过程。