机器学习之随机森林(python调参)

余生颓废 提交于 2020-02-14 17:58:11

原理

随机森林的原理即将多个决策树放到一起做决断。
决策树原理详见:机器学习之决策树原理
森林:建立多个决策树放到一起,形成一个森林,将测试数据依次输入这多个决策树,得到最终结果。假设有三棵树,输入测试数据后依次得到1,1,0,那么对于分类问题来说,得到的结果为1;对于回归问题来说,得到的结果可以是平均数0.67。
随机:

  • 1、样本的选择随机性:假设有从1到10共十个样本,从这个样本中有放回地抽取六个样本,用这六个样本建立第一个决策树,而不是用所有的样本,这样可以避免过拟合。像以上这样取十次,建立十个决策树,则构成了一个随机森林。
  • 2、特征的选择随机性:像之前的那个例子一样,不一定哪个特征对最终结果有利或有害,所以构建每个决策树时并不用到所有特征,而是无放回地抽取其中几个特征。比如从总的八个特征中选出六个特征参与某个决策树的构建。

python实现

1、导入需要的库

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

2、导入数据

data = load_breast_cancer()
print(data.data.shape)
print(data.target)

3、建立随机森林

rfc = RandomForestClassifier(n_estimators=100,random_state=90)
score_pre = cross_val_score(rfc,data.data,data.target,cv=10).mean()
print(score_pre)

得到准确率为0.9648809523809524。

4、调参

模型复杂度和最终结果的泛化误差之间的关系可以用下图表示:
在这里插入图片描述
所以调参时可以依照下表顺序:
在这里插入图片描述

4.1 调整n_estimators

在这里我们选择学习曲线,当然也可以使用网格搜索(即GridSearchCV函数),但是只有学习曲线,才能看见趋势。我个人的倾向是,要看见n_estimators在什么取值开始变得平稳,是否一直推动模型整体准确率的上升等信息。

scorel = [] 
for i in range(35,45):    
	rfc = RandomForestClassifier(n_estimators=i, n_jobs=-1, andom_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()
4.2 调整max_depth
param_grid = {'max_depth':np.arange(1, 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_)

在这里,我们注意到,将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是剪枝参数,是减小复杂度的参数。 在这里,我们可以预言,我们已经非常接近模型的上限,模型很可能没有办法再进步了。

4.3 调整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的最小值,可见max_features升高之后,模型的准确率降低了。这说明,我们把模型往右推,模型的泛化误差增加了。前面用max_depth往左推,现在用max_features往右推,泛化误差都增加, 这说明模型本身已经处于泛化误差最低点,已经达到了模型的预测上限,没有参数可以左右的部分了。剩下的那些 误差,是噪声决定的,已经没有方差和偏差的舞台了。
如果是现实案例,我们到这一步其实就可以停下了,因为复杂度和泛化误差的关系已经告诉我们,模型不能再进步 了。调参和训练模型都需要很长的时间,明知道模型不能进步了还继续调整,不是一个有效率的做法。如果我们希望模型更进一步,我们会选择更换算法,或者更换做数据预处理的方式。

4.4 调整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的最小值,并且模型整体的准确率还降低了,这和max_depth的情况一致,参数把模型向左推,但是模型的泛化误差上升了。在这种情况下,我们显然是不要把这个参数设置起来的,就让它默认就好了。

4.5 调整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一样的结果,返回最小值并且模型整体的准确率降低了。

4.6 调整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_)

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

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)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!