写点什么

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

  • 2022-11-09
    山东
  • 本文字数:3869 字

    阅读完需:约 13 分钟

from sklearn.datasets import load_breast_cancerfrom sklearn.ensemble import RandomForestClassifierfrom sklearn.model_selection import GridSearchCVfrom sklearn.model_selection import cross_val_scoreimport matplotlib.pyplot as pltimport numpy as npimport pandas as pd
复制代码


data = load_breast_cancer()
data.data.shape # 特征样本比小,模型很有可能会过拟合---(569, 30)
np.unique(data.target) # 二分类问题---array([0, 1])
复制代码


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


在这里我们选择学习曲线,也可以使用网格搜索,但是只有学习曲线,才能看见趋势要看见 n_estimators 在什么取值开始变得平稳,是否一直推动模型整体准确率的上升等信息第一次的学习曲线,可以先用来帮助我们划定范围,我们取每十个数作为一个阶段,来观察 n_estimators 的变化如何引起模型整体准确率的变化


scorel = []for i in range(0,200,10):    rfc = RandomForestClassifier(n_estimators=i+1                                ,random_state=0                                )    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()---0.9667844179414052 111
复制代码



可以看到在大概 20 以后学习曲线就区域平稳并在一个区域内波动,这里为了演示选择 25-35。其实可以选择更大一点,但没必要选择此时的最大值 111,因为 n_estimators 足够大时,其不再是决定随机森林表现的决定性因素,我们只需要选择一个较大的即可(一般认为不同 n_estimators 与已知最大相差小于 0.001)


scorel = []for i in range(25,35):    rfc = RandomForestClassifier(n_estimators=i                                ,random_state=0                                )    score = cross_val_score(rfc,data.data,data.target,cv=10).mean()    scorel.append(score)
print(max(scorel),[*range(25,35)][scorel.index(max(scorel))])plt.figure(figsize=[20,5])plt.plot(range(25,35),scorel)plt.show()---0.9667541699075274 25
复制代码



选定 n_estimators=25


接下来就进入网格搜索,我们将使用网格搜索对参数一个个进行调整。为什么我们不同时调整多个参数,原因有两个:同时调整多个参数会运行非常缓慢。同时调整多个参数,会让我们无法理解参数的组合是怎么得来的,所以即便网格搜索调出来的结果不好,我们也不知道从哪里去改。在这里,为了使用复杂度-泛化误差方法(方差-偏差方法),我们对参数进行一个个地调整。


有一些参数是没有参照的,很难说清一个范围,这种情况下我们使用学习曲线,看趋势从曲线跑出的结果中选取一个更小的区间,再跑曲线、网格搜索有一些参数(criterion)是可以找到一个范围的,或者说我们知道他们的取值和随着他们的取值,模型的整体准确率会如何变化,这样的参数我们就可以直接跑网格搜索


首先调整 max_depth


param_grid = {"max_depth":np.arange(1,20,1)}
rfc = RandomForestClassifier(n_estimators=25 ,random_state=0 )GS = GridSearchCV(rfc,param_grid,cv=10)GS.fit(data.data,data.target)
GS.best_params_ # 这里的7为最佳值,有可能是7=8=……≈n但是只显示了7---{'max_depth': 7}
GS.best_score_---0.9666080843585237
复制代码


用学习曲线的方式验证


scorel = []for i in range(1,50,3):    rfc = RandomForestClassifier(n_estimators=25                                ,random_state=0                                ,max_depth=i                                )    score = cross_val_score(rfc,data.data,data.target,cv=10).mean()    scorel.append(score)
print(max(scorel),scorel.index(max(scorel))*3+1)# 这里实际上就是返回了最大值,因为7≈11≈……≈nplt.figure(figsize=(16,5))plt.plot(range(1,50,3),scorel)plt.show()---0.9667854982283295 7
复制代码



其实这里 7 是最大的 score,但是和不限制的情况相差不到 0.001,所以我们这里不计入


(10, 0.9667541699075274), (13, 0.9667541699075274), (16, 0.9667541699075274)
复制代码


但这也告诉我们,模型实际上是有向左移动的空间的,只是很小


个人感觉

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

param_grid = {}
rfc = RandomForestClassifier()
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)

即使我们使用的参数都一样,但二者分数仍然后差距,可能是因为对分数的处理不同例如上面对于 max_depth 网格搜索认为 max_depth=7 模型最优,对应 score 为 0.9666080843585237 学习曲线认为 max_depth=7 模型最优,对应的 score 为 0.9667854982283295

还有网格搜索当达到参数阈值的时候,模型 scores 等于网格搜索的默认 score,而不是学习曲线的模型 score


max_features 是唯一一个即能够将模型往左(低方差高偏差)推,也能够将模型往右(高方差低偏差)推的参数。因此,我们可以用 max_features 验证模型是否有向右移动的空间。我们需要根据调参前,模型所在的位置(在泛化误差最低点的左边还是右边)来决定我们要将 max_features 往哪边调。现在模型位于图像右侧,我们要证明其不能再向右,也就是 max_features 不能比默认更大。max_features 的默认最小值是 sqrt(n_features),因此我们使用这个值作为调参范围的最小值。


param_grid = {"max_features":np.arange(5,30,1)}
rfc = RandomForestClassifier(n_estimators=25 ,random_state=0 )GS = GridSearchCV(rfc,param_grid,cv=10)GS.fit(data.data,data.target)
GS.best_params_# 也就是默认sqr n,没有右移空间---{'max_features': 5}
GS.best_score_---0.9666080843585237
复制代码


要左移模型我们先调整 min_samples_leaf


param_grid = {"min_samples_leaf":np.arange(1,10,1)}
rfc = RandomForestClassifier(n_estimators=25 ,random_state=0 )GS = GridSearchCV(rfc,param_grid,cv=10)GS.fit(data.data,data.target)
GS.best_params_---{'min_samples_leaf': 1}
GS.best_score_---0.9666080843585237
复制代码


对于 min_samples_leaf,我们调整它会将模型向左推的过多,模型的泛化误差上升了。在这种情况下,我们显然是不要把这个参数设置起来的,就让它默认就好了。


尝试 min_samples_split


param_grid = {"min_samples_split":np.arange(2,40,1)}
rfc = RandomForestClassifier(n_estimators=25 ,random_state=0 )GS = GridSearchCV(rfc,param_grid,cv=10)GS.fit(data.data,data.target)
GS.best_params_---{'min_samples_split': 17}
GS.best_score_---0.968365553602812
scorel = []for i in range(2,40,1): rfc = RandomForestClassifier(n_estimators=25 ,random_state=0 ,max_features=5 ,min_samples_leaf=1 ,min_samples_split=i ) score = cross_val_score(rfc,data.data,data.target,cv=10).mean() scorel.append(score)
print(max(scorel),scorel.index(max(scorel))+2)plt.figure(figsize=(20,5))plt.plot(range(2,40,1),scorel)plt.xticks(range(2,40,1))plt.show()---0.9685388039063175 17
复制代码



其实不知道为啥这有个波峰,但种种迹象都告诉我们,该模型有向左移的空间,没有向右移的空间


最后尝试一下 criterion


param_grid = {"criterion":['gini','entropy']}
rfc = RandomForestClassifier(n_estimators=25 ,random_state=0 ,min_samples_split=17 )GS = GridSearchCV(rfc,param_grid,cv=10)GS.fit(data.data,data.target)
GS.best_params_---{'criterion': 'gini'}
GS.best_score_---0.968365553602812
复制代码


在这里我们也能看出,无论是学习曲线还是网格搜索,都认为 min_samples_split=17 是最好的取值。但是二者得到的 score 是不同的网格搜索 0.968365553602812,学习曲线 0.9685388039063175


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


视频作者:菜菜TsaiTsai链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili


发布于: 刚刚阅读数: 3
用户头像

还未添加个人签名 2022-09-14 加入

还未添加个人简介

评论

发布
暂无评论
随机森林-随机森林在乳腺癌数据上的调参_Python_烧灯续昼2002_InfoQ写作社区