《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例

随机森林

  • 随机森林 - 概述
    • 集成算法概述
    • sklearn中的集成算法
  • 随机森林分类器 RandomForestClassifier
    • 重要参数
      • 控制基评估器的参数
      • n_estimators:基评估器的数量
      • 【建立一片森林】
      • random_state:控制森林生成模式的随机性
      • bootstrap:控制抽样技术
    • 重要属性
      • oob_score_:袋外数据测试模型准确度
      • estimators_:查看森林中树的状况
    • 重要接口:apply、fit、predict、score
  • 随机森林回归器 RandomForestRegressor
  • *机器学习中调参的基本思想
    • *泛化误差:衡量模型在未知数据上的准确率的指标
  • **实例:随机森林在乳腺癌数据上的调参

《菜菜的机器学习sklearn课堂》笔记目录 + 课件

随机森林 - 概述

集成算法概述

集成学习(ensemble learning) 是时下非常流行的机器学习算法,它本身不是一个单独的机器学习算法,而是通过在数据上构建多个模型集成所有模型的建模结果

几乎所有机器学习领域都可以看到集成学习的身影,现实中集成学习也有很大作用:

  • 市场营销模拟的建模
  • 统计客户来源,保留和流失
  • 预测疾病的风险和病患者的易感性
  • 在现在的算法竞赛中,随机森林梯度提升树(GBDT)Xgboost等集成算法随处可见

集成算法的目标:集成算法会考虑多个评估器的建模结果,汇总之后得到一个综合的结果,以此来获取比单个模型更好的回归或分类表现

多个模型集成成为的模型叫做集成评估器(ensemble estimator),组成集成评估器的每个模型都叫做基评估器(base estimator)。通常来说,有三类集成算法:

  • 装袋法(Bagging)
    装袋法的核心思想是构建多个相互独立的评估器,然后对其预测进行平均或多数表决原则来决定集成评估器的结果。装袋法的代表模型就是随机森林
  • 提升法(Boosting)
    提升法中,基评估器是相关的,是按顺序一一构建的。其核心思想是结合弱评估器的力量一次次对难以评估的样本进行预测,从而构成一个强评估器。提升法的代表模型有Adaboost梯度提升树
  • stacking

《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第1张图片

sklearn中的集成算法

sklearn中的集成算法模块ensemble

类的功能
ensemble.AdaBoostClassifier AdaBoost分类
ensemble.AdaBoostRegressor Adaboost回归
ensemble.BaggingClassifier 装袋分类器
ensemble.BaggingRegressor 装袋回归器
ensemble.ExtraTreesClassifier Extra-trees分类(超树,极端随机树)
ensemble.ExtraTreesRegressor Extra-trees回归
ensemble.GradientBoostingClassifier 梯度提升分类
ensemble.GradientBoostingRegressor 梯度提升回归
ensemble.IsolationForest 隔离森林
ensemble.RandomForestClassifier 随机森林分类
ensemble.RandomForestRegressor 随机森林回归
ensemble.RandomTreesEmbedding 完全随机树的集成
ensemble.VotingClassifier 用于不合适估算器的软投票/多数规则分类器

集成算法中有一半以上都是树的集成模型,可见决策树在集成中必定效果很好。
我们会以随机森林为例,慢慢揭开集成算法的神秘面纱。

复习:sklearn中的决策树

随机森林分类器 RandomForestClassifier

class sklearn.ensemble.RandomForestClassifier (
	n_estimators=10, 
	criterion=’gini’, 
	max_depth=None,
	min_samples_split=2, 
	min_samples_leaf=1, 
	min_weight_fraction_leaf=0.0, 
	max_features=’auto’,
	max_leaf_nodes=None, 
	min_impurity_decrease=0.0, 
	min_impurity_split=None, 
	bootstrap=True, 
	oob_score=False,
	n_jobs=None, 
	random_state=None, 
	verbose=0, 
	warm_start=False, 
	class_weight=None
)

随机森林是非常具有代表性的Bagging集成算法,它的所有基评估器都是决策树
分类树组成的森林就叫做随机森林分类器,回归树所集成的森林就叫做随机森林回归器。

这一节主要学习 RandomForestClassifier随机森林分类器

重要参数

控制基评估器的参数

参数 含义
criterion 不纯度的衡量指标,有基尼系数和信息熵两种选择
max_depth 树的最大深度,超过最大深度的树枝都会被剪掉
min_samples_leaf 一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生
min_samples_split 一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分枝,否则分枝就不会发生
max_features max_features限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃,默认值为总特征个数开平方取整
min_impurity_decrease 限制信息增益的大小,信息增益小于设定数值的分枝不会发生

单个决策树的准确率越高,随机森林的准确率也会越高,因为装袋法是依赖于平均值或者少数服从多数原则来决定集成的结果的。

n_estimators:基评估器的数量

n_estimators 是森林中树木的数量,即基评估器的数量

  • 一般来说,n_estimators越大,模型的效果往往越好
  • 但是任何模型都有决策边界,n_estimators达到一定的程度之后,随机森林的精确性往往不再上升或开始波动;并且n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越长。对于这个参数,我们是渴望在训练难度和模型效果之间取得平衡。

n_estimators的默认值在现有版本的sklearn中是10,但是在即将更新的0.22版本中,这个默认值会被修正为100。这个修正显示出了使用者的调参倾向——要更大的n_estimators

【建立一片森林】

树模型的优点是简单易懂,可视化之后的树人人都能够看懂,可惜随机森林无法被可视化。所以为了更加直观地体会随机森林的效果,我们进行一个随机森林和单个决策树效益的对比。我们依然使用红酒数据集。

1、导入我们需要的包

%matplotlib inline
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine

2. 导入需要的数据集

wine = load_wine()
wine.data.shape #178行,13个标签
wine.target

3、复习:sklearn建模的基本流程

from sklearn.model_selection import train_test_split

#划分30%的数据作为测试集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data, wine.target, test_size=0.3)

clf = DecisionTreeClassifier(random_state=0) #建立模型: 决策树
rfc = RandomForestClassifier(random_state=0) #建立模型: 随机森林

clf = clf.fit(Xtrain, Ytrain) # 训练模型: 决策树
rfc = rfc.fit(Xtrain, Ytrain) # 训练模型: 随即森林

score_c = clf.score(Xtest, Ytest) #返回预测的准确度: 随机森林
score_r = rfc.score(Xtest, Ytest) #返回预测的准确度: 决策树

# 打印出准确度
print("single Tree:{}".format(score_c),
      "Random Forest:{}".format(score_r))
single Tree:0.9444444444444444 Random Forest:0.9814814814814815

可见随机森林默认就比决策树准确度要高。

4、画出随机森林和决策树在一组交叉验证下的效果对比

交叉验证
将数据集划分为n份,依次取每一份做测试集,每n-1份做训练集,多次训练模型以观测模型稳定性的方法

from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt

# 随机森林
rfc = RandomForestClassifier(n_estimators=25)
rfc_s = cross_val_score(rfc, wine.data, wine.target, cv=10)

# 决策树
clf = DecisionTreeClassifier()
clf_s = cross_val_score(clf, wine.data, wine.target, cv=10)

plt.plot(range(1,11), rfc_s, label = "RandomForest")
plt.plot(range(1,11), clf_s, label = "Decision Tree")
plt.legend()
plt.show()

《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第2张图片
另一种更加简单有趣的写法:

label = "RandomForest"
for model in [RandomForestClassifier(n_estimators=25),DecisionTreeClassifier()]:
	score = cross_val_score(model,wine.data, wine.target, cv=10)
	print("{}:".format(label)),print(score.mean())
	plt.plot(range(1,11),score,label = label)
	plt.legend()
	label = "DecisionTree"

《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第3张图片
5、画出随机森林和决策树在十组交叉验证下的效果对比

rfc_l = []
clf_l = []
for i in range(10):
    rfc = RandomForestClassifier(n_estimators=25)
    rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
    rfc_l.append(rfc_s)
    
    clf = DecisionTreeClassifier()
    clf_s = cross_val_score(clf,wine.data,wine.target,cv=10).mean()
    clf_l.append(clf_s)

plt.plot(range(1,11), rfc_l, label="Random Forest")
plt.plot(range(1,11), clf_l, label="Decision Tree")
plt.legend()
plt.show()

《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第4张图片
6、n_estimators的学习曲线

#####【TIME WARNING: 2mins 30 seconds】#####
superpa = []
for i in range(200):
    rfc = RandomForestClassifier(n_estimators=i+1,n_jobs=-1)
    rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
    superpa.append(rfc_s)
print(max(superpa), superpa.index(max(superpa))) # 0.9888888888888889 53
plt.figure(figsize=[20,5])
plt.plot(range(1,201),superpa)
plt.show()

《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第5张图片

random_state:控制森林生成模式的随机性

《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第6张图片
思考一个问题:
我们说袋装法服从多数表决原则或对基分类器结果求平均,这即是说:我们默认森林中的每棵树应该是不同的,并且会返回不同的结果
设想一下,如果随机森林里所有的树的判断结果都一致(全判断对或全判断错),那随机森林无论应用何种集成原则来求结果,都应该无法比单棵决策树取得更好的效果才对。但我们使用了一样的类DecisionTreeClassifier,一样的参数,一样的训练集和测试集,为什么随机森林里的众多树会有不同的判断结果?

随机森林中其实也有random_state,用法和分类树中相似:

  • 在分类树中,一个random_state只控制生成一棵树
  • 随机森林中的random_state控制的是生成森林的模式,而非让一个森林中只有一棵树
rfc = RandomForestClassifier(n_estimators=20, random_state=2)
rfc = rfc.fit(Xtrain, Ytrain)
#随机森林的重要属性之一: estimators, 查看森林中树的状况
rfc.estimators_[0].random_state
for i in range(len(rfc.estimators_)):
    print(rfc.estimators_[i].random_state)

我们可以观察到:当random_state固定时,随机森林中生成是一组固定的树,但每棵树依然是不一致的,这是用”随机挑选特征进行分枝“的方法得到的随机性。并且我们可以证明,当这种随机性越大的时候,袋装法的效果一般会越来越好。用袋装法集成时,基分类器应当是相互独立的,是不相同的。

但这种做法的局限性是很强的,当我们需要成千上万棵树的时候,数据不一定能够提供成千上万的特征来让我们构筑尽量多尽量不同的树。因此,除了random_state。我们还需要其他的随机性。

bootstrap:控制抽样技术

要让基分类器尽量都不一样,一种很容易理解的方法是使用不同的训练集来进行训练,而袋装法正是通过有放回的随机抽样技术来形成不同的训练数据,bootstrap就是用来控制抽样技术的参数

在一个含有n个样本的原始训练集中,我们进行有放回的随机抽样技术

  • 每次采样 1 个样本,并在抽取下一个样本之前将该样本放回原始训练集
    也就是说下次采样时这个样本依然可能被采集到
    《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第7张图片
  • 这样采集 n 次,最终得到一个和原始训练集一样大的,n个样本组成的自助集

由于是随机采样,这样每次的自助集和原始数据集不同,和其他的采样集也是不同的。这样我们就可以自由创造取之不尽用之不竭,并且互不相同的自助集,用这些自助集来训练我们的基分类器,我们的基分类器自然也就各不相同了。

默认bootstrap=True,代表采用这种有放回的随机抽样技术;通常不会设置为False。

重要属性

oob_score_:袋外数据测试模型准确度

然而有放回抽样也会有自己的问题。由于是有放回,一些样本可能在同一个自助集中出现多次,而其他一些却可能被忽略,一般来说,自助集大约平均会包含63%的原始数据。因为每一个样本被抽到某个自助集中的概率为:
1 − ( 1 − 1 n ) n 1 - ( 1 - \frac 1 n)^n 1(1n1)n
当n足够大时,这个概率收敛于 1 − ( 1 e ) 1-(\frac 1 e) 1(e1),约等于0.632,因此会有约37%的训练数据被浪费掉,没有参与建模。这些数据被称为袋外数据(out of bag data,简写为oob)
在使用随机森林时,我们可以不划分测试集和训练集,使用袋外数据来测试我们的模型。

当然,这也不是绝对的,当n和n_estimators都不够大的时候,很可能就没有数据掉落在袋外,自然也就无法使用oob数据来测试模型了。

如果希望用袋外数据来测试,则需要在实例化时就设置oob_score=True。训练完毕之后,我们可以用随机森林的另一个重要属性:oob_score_ 来查看我们的在袋外数据上测试的结果:

#无需划分训练集和测试集
rfc = RandomForestClassifier(n_estimators=25,oob_score=True)
rfc = rfc.fit(wine.data,wine.target)

#重要属性oob_score_
rfc.oob_score_

estimators_:查看森林中树的状况

rfc = RandomForestClassifier(n_estimators=20, random_state=2)
rfc = rfc.fit(Xtrain, Ytrain)
#随机森林的重要属性之一: estimators, 查看森林中树的状况
rfc.estimators_

重要接口:apply、fit、predict、score

随机森林的接口与决策树完全一致,因此也有4个常用接口:apply、fit、predict、score。

  • scoire
    《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第8张图片
  • apply
    《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第9张图片

除此之外,还需要注意随机森林的predict_proba接口,这个接口返回每个测试样本对应的被分到每一类标签的概率,标签有几个分类就返回几个概率。

  • 如果是二分类问题,则predict_proba返回的数值大于0.5的,被分为1,小于0.5的,被分为0。
    《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第10张图片

传统的随机森林是利用袋装法中的规则,平均或少数服从多数来决定集成的结果,而sklearn中的随机森林是平均每个样本对应的predict_proba返回的概率,得到一个平均概率,从而决定测试样本的分类。

从红酒数据集的表现上来看,随机森林的效用比单纯的决策树要强上不少。

随机森林回归器 RandomForestRegressor

略…

*机器学习中调参的基本思想

大多数的机器学习相关的书都是遍历各种算法和案例,为大家讲解各种各样算法的原理和用途,但却对调参探究甚少,主要原因是:

  • 调参的方式总是根据数据的状况而定,没要办法一概而论
  • 对于调参,其实大家也都没有特别好的办法

通过画学习曲线,或者网格搜索,我们能够探索到调参边缘(代价可能是训练一次模型要跑三天三夜),但是在现实中,高手调参恐怕还是多依赖于经验;而这些经验来源于:

  • 非常正确的调参思路和方法
  • 对模型评估指标的理解
  • 对数据的感觉和经验
  • 用洪荒之力去不断地尝试

在机器学习中,衡量模型在未知数据上的准确率的指标叫做泛化误差(Genelization error)

*泛化误差:衡量模型在未知数据上的准确率的指标

未知数据:测试集、袋外数据
当模型在未知数据上表现糟糕时,我们说模型的泛化程度不够,泛化误差大,模型的效果不好。

泛化误差受模型的结构(复杂度)影响,下图准确地描绘了泛化误差与模型复杂度的关系:

  • 当模型太复杂,模型就会过拟合,泛化能力就不够,所以泛化误差大
  • 当模型太简单,模型就会欠拟合,拟合能力就不够,泛化误差也会大
  • 只有当模型的复杂度刚刚好的才能够达到泛化误差最小的目标
    《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第11张图片

对树模型来说,树越茂盛,深度越深,枝叶越多,模型就越复杂;所以树模型是天生位于图的右上角的模型。随机森林是以树模型为基础,所以随机森林也是天生复杂度高的模型。

随机森林的参数,都是向着一个目标去:减少模型的复杂度,把模型往图像的左边移动,防止过拟合。当然,调参无绝对,也有天生处于图像左边的随机森林,所以调参之前,我们要先判断:模型现在究竟处于图像的哪一边。

泛化误差的背后其实是 “偏差-方差困境”,原理十分复杂,我们只需记住四点:

  1. 模型太复杂或者太简单,都会让泛化误差高,我们追求的是位于中间的平衡点
  2. 模型太复杂就会过拟合,模型太简单就会欠拟合
  3. 对树模型和树的集成模型来说,树的深度越深,枝叶越多,模型越复杂
  4. 树模型和树的集成模型的目标,都是减少模型复杂度,把模型往图像的左边移动

老师基于经验,对各个参数对模型的影响程度做了一个排序:

《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第12张图片

有了以上的知识储备,我们现在也能够通过参数的变化来了解,模型什么时候到达了极限,当复杂度已经不能再降低的时候,我们就不必再调整了,因为调整大型数据的参数是一件非常费时费力的事。

除了学习曲线和网格搜索,我们现在有了基于对模型和正确的调参思路的“推测”能力,这能够让我们的调参能力更上一层楼。

**实例:随机森林在乳腺癌数据上的调参

调参时除了一些参数设置会变化,其他代码几乎是一样的,主要学习调参思路!

乳腺癌数据是sklearn自带的分类数据之一。

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

data

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

3、进行一次简单的建模,看看模型本身在数据集上的效果

rfc = RandomForestClassifier(n_estimators=100, random_state=90)  #建100棵树的随机森林,90是随便输的
score_pre = cross_val_score(rfc, data.data, data.target, cv=10).mean() #交叉验证
score_pre
# 这里可以看到,随机森林在乳腺癌数据上的表现本就还不错
# 在现实数据集上,基本上不可能什么都不调就看到95%以上的准确率

0.9648809523809524

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

"""
在这里我们选择学习曲线,可以使用网格搜索吗?
	-可以,但是只有学习曲线,才能看见趋势
我个人的倾向是,要看见n_estimators在什么取值开始变得平稳,
	是否一直推动模型整体准确率的上升等信息,
	第一次的学习曲线,可以先用来帮助我们划定范围,
	我们取每十个数作为一个阶段,来观察n_estimators的变化如何引起模型整体准确率的变化
"""
#####【TIME WARNING: 30 seconds】#####
scorel = []
for i in range(0,200,10):
	# 令 n_estimators = 1,11,21,31...,191 
    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) #将每次n_estimators不同的交叉验证的准确度放入scorel列表
    
#打印最高的交叉验证准确度及其索引
#list.index([object]) 返回这个object在列表list中的索引
print(max(scorel),(scorel.index(max(scorel))*10)+1) 

plt.figure(figsize=[20,5])
plt.plot(range(1,201,10),scorel)
plt.show()

0.9631265664160402 71
《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第13张图片
5、在第4步确定好的范围内,进一步细化学习曲线
第4步中,输出的精确度最高的n_estimators,索引是71,因此我们将其范围调到 65~85

scorel = []
for i in range(64,84):
	# 令 n_estimators = 65,66,67...,85
    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) #将每次n_estimators不同的交叉验证的准确度放入scorel列表
    
#打印最高的交叉验证准确度及其索引
#list.index([object]) 返回这个object在列表list中的索引
print(max(scorel),([*range(64,84)][scorel.index(max(scorel))]))

plt.figure(figsize=[20,5])
plt.plot(range(64,84),scorel)
plt.show()

0.9666353383458647 72
《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第14张图片
调整n_estimators后,模型的准确率从0.963...到了0.966...

接下来就进入网格搜索,我们将使用网格搜索对参数一个个进行调整。

为什么我们不同时调整多个参数呢?原因有两个:

  1. 同时调整多个参数会运行非常缓慢,在课堂上我们没有这么多的时间。
  2. 同时调整多个参数,会让我们无法理解参数的组合是怎么得来的,即便网格搜索调出来的结果不好,我们也不知道从哪里去改。在这里,为了使用复杂度-泛化误差方法(方差-偏差方法),我们对参数进行一个个地调整。

6、为网格搜索做准备,书写网格搜索的参数

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

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

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

对于大型数据集,可以尝试从1000来构建,先输入1000,每100个叶子一个区间,再逐渐缩小范围
param_grid = {'max_leaf_nodes':np.arange(25,50,1)}
 
有一些参数是可以找到一个范围的,或者说我们知道他们的取值和
随着他们的取值模型的整体准确率会如何变化,这样的参数我们就可以直接跑网格搜索

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

根据前面总结的表格,我们可以从影响最大的参数开始调《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第15张图片

#调整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_

{'max_depth': 6}

GS.best_score_

0.9631265664160402

在这里,我们注意到,调整max_depth之后,模型的准确率下降了

  • 限制max_depth,是让模型变得简单,把模型向左推,而模型整体的准确率下降了,即整体的泛化误差上升了,这说明模型现在位于图像左边,即泛化误差最低点的左边(偏差为主导的一边)
    《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第16张图片

通常来说,随机森林应该在泛化误差最低点的右边,树模型应该倾向于过拟合,而不是拟合不足;但是这和数据集本身有关,也有可能是我们调整的n_estimators对于数据集来说太大,因此将模型拉到泛化误差最低点去了。然而,既然我们追求最低泛化误差,那我们就保留这个n_estimators,除非有其他的因素可以帮助我们达到更高的准确率。

当模型位于图像左边时,我们需要的是增加模型复杂度(增加方差,减少偏差)的选项,因此max_depth应该尽量大,min_samples_leaf和min_samples_split都应该尽量小。

这几乎是在说明,除了max_features,我们没有任何参数可以调整了,因为max_depth,min_samples_leaf和min_samples_split是剪枝参数,是减小复杂度的参数。

《菜菜的机器学习sklearn课堂》随机森林应用泛化误差调参实例_第17张图片

在这里,我们可以预言,我们已经非常接近模型的上限,模型很可能没有办法再进步了。
那我们就来调整一下max_features,看看模型如何变化。

8、调整max_features(将模型向右移)

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

"""
max_features是唯一一个既能够将模型往左(低方差高偏差)推,也能够将模型往右(高方差低偏差)推的参数。
我们需要根据调参前,模型所在的位置(在泛化误差最低点的左边还是右边)来决定我们要将max_features往哪边调。
现在模型位于图像左侧,我们需要的是更高的复杂度,因此我们应该把max_features往更大的方向调整,
可用的特征越多,模型才会越复杂。max_features的默认最小值是sqrt(n_features),
因此我们使用这个值作为调参范围的最小值。
"""

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

GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_

{'max_features': 6}

GS.best_score_

0.968421052631579

诶,这里和老师不一样呀,老师下降了,但是我却上升了…也说明了:调参无绝对

9、调整min_samples_leaf

#调整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=39,
                             random_state=90)

GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_

{'min_samples_leaf': 4}

GS.best_score_

0.9613721804511279

10、不懈努力,继续尝试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_

{'min_samples_split': 3}

GS.best_score_

0.9613721804511279

11、最后尝试一下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_

{'criterion': 'entropy'}

GS.best_score_

0.9649122807017543

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

rfc = RandomForestClassifier(n_estimators=72,
                             random_state=90,
                             max_features=6,
                             #min_samples_leaf=4, 
                             #min_samples_split=3,
                            )
score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
score

0.9648809523809525

score - score_pre

1.1102230246251565e-16


在整个调参过程之中,我们首先调整了 n_estimators(无论如何都请先走这一步);然后调整max_depth,通过max_depth产生的结果来判断模型位于复杂度-泛化误差图像的哪一边,从而选择我们应该调整的参数和调参的方向。

  • 如果感到困惑,也可以画很多学习曲线来观察参数会如何影响我们的准确率,选取学习曲线中单调的部分来放大研究(如同我们对n_estimators做的)。学习曲线的拐点也许就是我们一直在追求的,最佳复杂度对应的泛化误差最低点(也是方差和偏差的平衡点)。

你可能感兴趣的:(python,机器学习,随即森林,泛化误差,调参)