随机森林在乳腺癌数据上的调参


前言

通过随机森林在乳腺癌数据上的调参来了解调参的思想


乳腺癌数据调参

1. 导入库

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier #随机森林分类模型
from sklearn.model_selection import cross_val_score #交叉验证
from sklearn.model_selection import GridSearchCV #网格搜索
from sklearn.datasets import load_breast_cancer #乳腺癌数据

2. 导入数据并探索

data = load_breast_cancer()

data.data.shape
> (569, 30)
#可以看到,乳腺癌数据集有569条记录,30个特征,单看维度虽然不算太高,
#但是样本量非常少。过拟合的情况可能存在

3. 简单建模,看模型本身在数据集上的效果

rfc = RandomForestClassifier(random_state=90,n_estimators=100)#实例化
score_pre = cross_val_score(rfc,data.data,data.target,cv=10).mean()#交叉验证

score_pre
>0.9648809523809524

#这里可以看到,随机森林在乳腺癌数据上的表现本就还不错,在现实数据集上,
#基本上不可能什么都不调就看到95%以上的准确率

4. 随机森林调整的第一步:无论如何先来调n_estimators

推荐使用学习曲线来调整n_estimators,学习曲线可以观测到趋势,第一次的学习曲线,可以先用来帮助我们划定范围,我们取每十个数作为一个阶段,来观察n_estimators的变化如何引起模型整体准确率的变化

scorel = []#储存不同n_estimators的评分

#通常n_estimators在200以内最好
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)
    
#找出最大的评分并通过索引来找出其对应的取得最大值的时候的具体参数值
#上面是以10为步长,所以索引需要通过处理才可得到相应的取值
print(max(scorel),(scorel.index(max(scorel))*10)+1)
plt.plot(range(1,201,10),scorel)
plt.show()

在这里插入图片描述

  • 由上方可得当n_estimators=71时最大

5. 在确定好的范围内,进一步细化学习曲线

scorel = []
#由上方得出的图和数来看,粗略在71,71在50到75之内,所以对50到75范围内进行学习曲线的细化,
#看在这个范围内71是不是最大的
for i in range(50,75):
	#实例化
    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),scorel.index(max(scorel))+50)
plt.plot(range(50,75),scorel)
plt.show()

在这里插入图片描述

  • 由细化的学习曲线可得,当n_estimators取73时比取71时还要好

注意

  • 接下来的网格搜索时一个参数一个参数的来试
  • 在此不同时调整多个参数的原因是运行速度过于缓慢
  • 以后的可以尝试多个参数的调试

6. 使用网格搜索和学习曲线的大概判断方法

有一些参数是没有参照的,很难说清一个范围,这种情况下我们使用学习曲线,看趋势从曲线跑出的结果中选取一个更小的区间,再跑曲线

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)}

7. 开始按照参数对模型整体准确率的影响程度进行调参,首先调整max_depth

scorel = []

# 一般根据数据的大小来进行一个试探,乳腺癌数据很小,所以可以采用1~10,或者1~20这样的试探
# 但对于像digit recognition那样的大型数据来说,我们应该尝试30~50层深度(或许还不足够
# 更应该画出学习曲线,来观察深度对模型的影响

for i in range(1,21):
    rfc = RandomForestClassifier(n_estimators=73 #n_estimators是上面得出的
                                ,random_state=90 #random_state要与上面相同
                                ,max_depth=i)
    score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
    scorel.append(score)
    
#索引是从0开始的,取值是从1开始,所以需要+1
print(max(scorel),scorel.index(max(scorel))+1)
plt.plot(range(1,21),scorel)
plt.show()

在这里插入图片描述

  • 设置max_depth参数的目的是降低模型的复杂度,但是通过所得结果来看添加max_depth之后,模型的评分并没有改变,说明降低模型复杂度并没有起到降低泛化误差的作用,那这个可能是模型本身并不是复杂度超过最泛化误差最低点的复杂度标准,有可能是小于最低点泛化误差的模型复杂度,这个时候如果要提高评分(降低泛化误差)需要对模型的复杂度进行提升来起到降低泛化误差的效果。

在这里插入图片描述

  • 如果添加了max_depth,评分降低了,那代表模型的复杂度处于最佳模型复杂度的左边,这个时候降低模型复杂度不会有任何的用处

8.调整max_features

#30的开平方是五点几,所以中间值为5,通过上面分析是要增加模型复杂度,所以让max_features增加
param_grid = {'max_features':np.arange(5,30,1)}
'''
max_features是唯一一个即能够将模型往左(低方差高偏差)推,也能够将模型往右(高方差低偏差)推的参数。我
们需要根据调参前,模型所在的位置(在泛化误差最低点的左边还是右边)来决定我们要将max_features往哪边调。
现在模型位于图像左侧,我们需要的是更高的复杂度,因此我们应该把max_features往更大的方向调整,可用的特征
越多,模型才会越复杂。max_features的默认最小值是sqrt(特征个数),因此我们使用这个值作为调参范围的
最小值。
'''

rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90
                            ,max_depth=8#可写可不写,因为等于8评分不变
                            )
                   
GV = GridSearchCV(rfc,param_grid,cv=10) #网格搜索
GV.fit(data.data,data.target) #训练
#最佳的参数取值
GV.best_params_
> {'max_features': 22}
#最佳参数取值下的评分
GV.best_score_
>0.968421052631579
  • 增加模型复杂度之后的评分上升了0.002左右,是一个非常大的进步

注意

如果是现实案例,我们到这一步其实就可以停下了,因为复杂度和泛化误差的关系已经告诉我们,模型不能再进步了。调参和训练模型都需要很长的时间,明知道模型不能进步了还继续调整,不是一个有效率的做法。如果我们希望模型更进一步,我们会选择更换算法,或者更换做数据预处理的方式(例如填补缺失值的方法)出于练习和探索的目的,我们继续调整我们的参数,看看预测得是否正确。

9. 调整min_samples_leaf

param_grid = {'min_samples_leaf':np.arange(1,1+10,1)}
#对于min_samples_split和min_samples_leaf,一般是从他们的最小值开始向上增加10或20
#面对高维度高样本量数据,如果不放心,也可以直接+50,对于大型数据,可能需要200~300的范围
#如果调整的时候发现准确率无论如何都上不来,那可以放心大胆调一个很大的数据,大力限制模型的复杂度

rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90
                            ,max_depth=8
                            ,max_features=22)
GV = GridSearchCV(rfc,param_grid,cv=10)
GV.fit(data.data,data.target)
#最佳的参数取值
GV.best_params_
> {'min_samples_leaf': 1}
#最佳参数取值下的评分
GV.best_score_
>0.968421052631579
  • 可以发现min_samples_leaf取得了最小值,庆幸的是泛化误差没有上升,还算幸运

10.继续尝试min_samples_split

param_grid = {'min_samples_split':np.arange(2,2+10,1)}
rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90
                            ,max_depth=8
                            ,max_features=22)
GV = GridSearchCV(rfc,param_grid,cv=10)
GV.fit(data.data,data.target)
#最佳的参数取值
GV.best_params_
> {'min_samples_split': 2}
#最佳参数取值下的评分
GV.best_score_
>0.968421052631579
  • 同min_samples_leaf相同

11. 最后尝试一下criterion

param_grid = {'criterion':['gini','entropy']}
rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90
                            ,max_depth=8
                            ,max_features=22
                            )
GV = GridSearchCV(rfc,param_grid,cv=10)
GV.fit(data.data,data.target)
#最佳的参数取值
GV.best_params_
> {'criterion': 'gini'}
#最佳参数取值下的评分
GV.best_score_
>0.968421052631579

12.调整完毕,总结最佳参数

rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90
                            ,max_depth=8
                            ,max_features=22
                            )
score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
score
  • 在这个例子里,最开始加max_depth评分没有改变,所以在开始的时候可加可不加,但是如果上面加了,在网格搜索里也有这个参数的话,那么最后使用的时候也需要带上这个参数,不然会影响通过网格搜索出来的评分

总结

在整个调参过程之中,我们首先调整了n_estimators(无论如何都请先走这一步),然后调整max_depth,通过max_depth产生的结果,来判断模型位于复杂度-泛化误差图像的哪一边,从而选择我们应该调整的参数和调参的方向。如果感到困惑,也可以画很多学习曲线来观察参数会如何影响我们的准确率,选取学习曲线中单调的部分来放大研究(如同我们对n_estimators做的)。学习曲线的拐点也许就是我们一直在追求的,最佳复杂度对应的泛化误差最低点(也是方差和偏差的平衡点)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值