sklearn专题二:随机森林

目录

1 概述

1.1 集成算法概述

1.2 sklearn中的集成算法

2 RandomForestClassifier

2.1 重要参数

2.1.1 控制基评估器的参数

2.1.2 n_estimators

3 RandomForestRegressor

3.1 重要参数,属性与接口

3.2 实例:用随机森林回归填补缺失值

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

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


 

1 概述

1.1 集成算法概述

集成学习(ensemble     learning)是时下非常流行的机器学习算法,它本身不是一个单独的机器学习算法,而是通过在数据上构建多个模型,集成所有模型的建模结果。基本上所有的机器学习领域都可以看到集成学习的身影,在  现实中集成学习也有相当大的作用,它可以用来做市场营销模拟的建模,统计客户来源,保留和流失,也可用来预  测疾病的风险和病患者的易感性。在现在的各种算法竞赛中,随机森林,梯度提升树(GBDT),Xgboost等集成   算法的身影也随处可见,可见其效果之好,应用之广。

集成算法的目标

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

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

sklearn专题二:随机森林_第1张图片

装袋法的核心思想是构建多个相互独立的评估器,然后对其预测进行平均或多数表决原则来决定集成评估器的结果。装袋法的代表模型就是随机森林。

提升法中,基评估器是相关的,是按顺序一一构建的。其核心思想是结合弱评估器的力量一次次对难以评估的样本进行预测,从而构成一个强评估器。提升法的代表模型有Adaboost和梯度提升树。

1.2 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

用于不合适估算器的软投票/多数规则分类器

 集成算法中,有一半以上都是树的集成模型,可以想见决策树在集成中必定是有很好的效果。

RandomForestClassifier

class (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,随机森林分类器。

2.1 重要参数

2.1.1 控制基评估器的参数

参数

含义

criterion

不纯度的衡量指标,有基尼系数和信息熵两种选择

max_depth

树的最大深度,超过最大深度的树枝都会被剪掉

min_samples_leaf

一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样  本,否则分枝就不会发生

min_samples_split

一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分  枝,否则分枝就不会发生

max_features

max_features限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃,  默认值为总特征个数开平方取整

min_impurity_decrease

限制信息增益的大小,信息增益小于设定数值的分枝不会发生

2.1.2 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
wine.target

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

from sklearn.model_selection import train_test_split
Xtain,Xtest,Ytain,Ytest=train_test_split(wine.data,wine.target,test_size=0.3)

clf=DecisionTreeClassifier(random_state=0)
clf=clf.fit(Xtain,Ytain)
score_c=clf.score(Xtest,Ytest)

rfc=RandomForestClassifier(random_state=0)
rfc=rfc.fit(Xtain,Ytain)
score_r=rfc.score(Xtest,Ytest)

print("Single Tree:{}".format(score_c)
     ,"Random Forest:{}".format(score_r)
     )

输出结果

Single Tree:0.9074074074074074 Random Forest:1.0

可以看出随机森林的效果比决策树好得多

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

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="Random Forest")
plt.plot(range(1,11),clf_s,label="Decision Tree")
plt.legend()
plt.show()

sklearn专题二:随机森林_第2张图片

 从图中可以看出,随机森林的效果比决策树的效果都是大于或者等于的。

5.画出随机森林和决策树在十组交叉验证下的效果对比

rfc_1=[]
clf_1=[]

for i in range(10):
    rfc=RandomForestClassifier(n_estimators=25)
    rfc_s=cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
    rfc_1.append(rfc_s)
    
    clf=DecisionTreeClassifier()
    clf_s=cross_val_score(clf,wine.data,wine.target,cv=10).mean()
    clf_1.append(clf_s)
    
plt.plot(range(1,11),rfc_1,label="Random Forest")
plt.plot(range(1,11),clf_1,label="Decision Tree")
plt.legend()
plt.show()

sklearn专题二:随机森林_第3张图片

是否有注意到,单个决策树的波动轨迹和随机森林一致?

再次验证了我们之前提到的,单个决策树的准确率越高,随机森林的准确率也会越高

6.n_estimators

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))) 
plt.figure(figsize=[20,5]) 
plt.plot(range(1,201),superpa)
plt.show()

sklearn专题二:随机森林_第4张图片

2.1.3 random_state 

随机森林的本质是一种装袋集成算法(bagging),装袋集成算法是对基评估器的预测结果进行平均或用多数表决    原则来决定集成评估器的结果。在刚才的红酒例子中,我们建立了25棵树,对任何一个样本而言,平均或多数表决  原则下,当且仅当有13棵以上的树判断错误的时候,随机森林才会判断错误。单独一棵决策树对红酒数据集的分类  准确率在0.85上下浮动,假设一棵树判断错误的可能性为0.2(ε),那20棵树以上都判断错误的可能性是:

其中,i是判断错误的次数,也是判错的树的数量,ε是一棵树判断错误的概率,(1-ε)是判断正确的概率,共判对

25-i次。采用组合,是因为25棵树中,有任意i棵都判断错误。

RandomForestRegressor

class sklearn.ensemble.RandomForestRegressor ( n_estimators=’warn’ , criterion=’mse’ , 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 )
所有的参数,属性与接口,全部和随机森林分类器一致。仅有的不同就是回归树与分类树的不同,不纯度的指标, 参数 Criterion 不一致。

3.1 重要参数,属性与接口

criterion
回归树衡量分枝质量的指标,支持的标准有三种:
1 )输入 "mse" 使用均方误差 mean squared error(MSE) ,父节点和叶子节点之间的均方误差的差额将被用来作为
特征选择的标准,这种方法通过使用叶子节点的均值来最小化 L2 损失
2 )输入 “friedman_mse” 使用费尔德曼均方误差,这种指标使用弗里德曼针对潜在分枝中的问题改进后的均方误差
3 )输入 "mae" 使用绝对平均误差 MAE mean absolute error ),这种指标使用叶节点的中值来最小化 L1 损失

其中 N 是样本数量, i 是每一个数据样本, fifi 是模型回归出的数值, yi 是样本点 i 实际的数值标签。所以 MSE 的本质,
其实是样本真实数据与回归结果的差异。 在回归树中, MSE 不只是我们的分枝质量衡量指标,也是我们最常用的衡
量回归树回归质量的指标 ,当我们在使用交叉验证,或者其他方式获取回归树的结果时,我们往往选择均方误差作
为我们的评估(在分类树中这个指标是 score 代表的预测准确率)。在回归中,我们追求的是, MSE 越小越好。
然而, 回归树的接口 score 返回的是 R 平方,并不是 MSE R 平方被定义如下:

其中 u 是残差平方和( MSE * N ), v 是总平方和, N 是样本数量, i 是每一个数据样本, fifi 是模型回归出的数值,yi 是样本点 i 实际的数值标签。 y 帽是真实数值标签的平均数。 R平方可以为正为负(如果模型的残差平方和远远大于 模型的总平方和,模型非常糟糕, R 平方就会为负),而均方误差永远为正。
值得一提的是, 虽然均方误差永远为正,但是 sklearn 当中使用均方误差作为评判标准时,却是计算 负均方误 neg_mean_squared_error 。这是因为 sklearn在计算模型评估指标的时候,会考虑指标本身的性质,均 方误差本身是一种误差,所以被 sklearn 划分为模型的一种损失 (loss) ,因此在 sklearn当中,都以负数表示。真正的 均方误差 MSE 的数值,其实就是 neg_mean_squared_error 去掉负号的数字。

 重要属性和接口

最重要的属性和接口,都与随机森林的分类器相一致,还是 apply, fifit, predict score最为核心。值得一提的是,随 机森林回归并没有 predict_proba这个接口,因为对于回归来说,并不存在一个样本要被分到某个类别的概率问 题,因此没有 predict_proba 这个接口。
随机森林回归用法
和决策树完全一致,除了多了参数 n_estimators
以下代码调出所有的检验方法
import sklearn
from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestRegressor
boston = load_boston()
regressor = RandomForestRegressor(n_estimators=100,random_state=0)
cross_val_score(regressor, boston.data, boston.target,cv=10,scoring = "neg_mean_squared_error")
sorted(sklearn.metrics.SCORERS.keys())

返回十次交叉验证的结果,注意在这里,如果不填写scoring = "neg_mean_squared_error",交叉验证默认的模型,衡量指标是R平方,因此交叉验证的结果可能有正也可能有负。而如果写上scoring,则衡量标准是负MSE,交叉验 证的结果只可能为负。

3.2 实例:用随机森林回归填补缺失值

我们从现实中收集的数据,几乎不可能是完美无缺的,往往都会有一些缺失值。面对缺失值,很多人选择的方式是 直接将含有缺失值的样本删除,这是一种有效的方法,但是有时候填补缺失值会比直接丢弃样本效果更好,即便我们其实并不知道缺失值的真实样貌。在 sklearn 中,我们可以使用 sklearn.impute.SimpleImputer来轻松地将均值,中值,或者其他最常用的数值填补到数据中,在这个案例中,我们将使用均值, 0,和随机森林回归来填补缺失值,并验证四种状况下的拟合状况,找出对使用的数据集来说最佳的缺失值填补方法。
1.导入需要的库
import sklearn
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_boston #一个标签是连续变量的数据集
from sklearn.impute import SimpleImputer  #填补缺失值的类
from sklearn.ensemble import RandomForestRegressor #导入随机森林回归系
from sklearn.model_selection import cross_val_score #导入交叉验证模块
2. 以波士顿数据集为例,导入完整的数据集并探索
dataset=load_boston()
dataset.data.shape  #(506, 13)
x_full,y_full=dataset.data,dataset.target
n_samples=x_full.shape[0]  #506
n_features=x_full.shape[1]  #13

3.为完整数据集放入缺失值

首先确定我们希望放入的缺失数据的比例,在这里我们假设是50%,那总共就要有3289个数据缺失
rng=np.random.RandomState(0)
missing_rate=0.5
n_missing_samples=int(np.floor(n_samples*n_features*missing_rate))
#np.floor向下取整,返回.0格式的浮点数
所有数据要随机遍布在数据集的各行各列当中,而一个缺失的数据会需要一个行索引和一个列索引
如果能够创造一个数组,包含3289个分布在0~506中间的行索引,和3289个分布在0~13之间的列索引,那我们就可 以利用索引来为数据中的任意3289个位置赋空值
然后我们用0,均值和随机森林来填写这些缺失值,然后查看回归的结果如何
missing_features=rng.randint(0,n_features,n_missing_samples)
missing_samples=rng.randint(0,n_samples,n_missing_samples)
missing_samples = rng.choice(dataset.data.shape[0],n_missing_samples,replace=False)
我们现在采样了 3289 个数据,远远超过我们的样本量 506 ,所以我们使用随机抽取的函数 randint。但如果我们需要 的数据量小于我们的样本量 506 ,那我们可以采用 np.random.choice 来抽样, choice会随机抽取不重复的随机数, 因此可以帮助我们让数据更加分散,确保数据不会集中在一些行中
missing_features=rng.randint(0,n_features,n_missing_samples)
missing_samples=rng.randint(0,n_samples,n_missing_samples)
x_missing=x_full.copy()
y_missing=y_full.copy()

x_missing[missing_samples,missing_features]=np.nan
x_missing=pd.DataFrame(x_missing)
转换成 DataFrame 是为了后续方便各种操作, numpy对矩阵的运算速度快到拯救人生,但是在索引等功能上却不如 pandas 来得好用
4.使用0和均值填补缺失值
#使用均值填充
from sklearn.impute import SimpleImputer 
imp_mean=SimpleImputer(missing_values=np.nan,strategy='mean')
x_missing_mean=imp_mean.fit_transform(x_missing)

#使用0填充
imp_0=SimpleImputer(missing_values=np.nan,strategy='constant',fill_value=0)
x_missing_0=imp_0.fit_transform(x_missing)

5.使用随机森林填充缺失值

任何回归都是从特征矩阵中学习,然后求解连续型标签y的过程,之所以能够实现这个过程,是因为回归算法认为,特征矩阵和标签之前存在着某种联系。实际上,标签和特征是可以相互转换的,比如说,在一个“用地区,环境,附近学校数 量”预测“房价”的问题中,我们既可以用“地区”,“环境”,“附近学校数量”的数据来预测“房价”,也可以反过来, 用“环境”,“附近学校数量”和“房价”来预测“地区”。而回归填补缺失值,正是利用了这种思想。 对于一个有n个特征的数据来说,其中特征T有缺失值,我们就把特征T当作标签,其他的n-1个特征和原本的标签组成新的特征矩阵。那对于T来说,它没有缺失的部分,就是我们的Y_test,这部分数据既有标签也有特征,而它缺失的部分,只有特征没有标签,就是我们需要预测的部分。
特征T不缺失的值对应的其他n-1个特征 + 本来的标签:X_train
特征T不缺失的值:Y_train
特征T缺失的值对应的其他n-1个特征 + 本来的标签:X_test
特征T缺失的值:未知,我们需要预测的Y_test
这种做法,对于某一个特征大量缺失,其他特征却很完整的情况,非常适用。
那如果数据中除了特征T之外,其他特征也有缺失值怎么办?
答案是遍历所有的特征,从缺失最少的开始进行填补(因为填补缺失最少的特征所需要的准确信息最少)。
填补一个特征时,先将其他特征的缺失值用0代替,每完成一次回归预测,就将预测值放到原本的特征矩阵中,再继续填 补下一个特征。每一次填补完毕,有缺失值的特征会减少一个,所以每次循环后,需要用0来填补的特征就越来越少。当 进行到最后一个特征时(这个特征应该是所有特征中缺失值最多的),已经没有任何的其他特征需要用0来进行填补了, 而我们已经使用回归为其他特征填补了大量有效信息,可以用来填补缺失最多的特征。 遍历所有的特征后,数据就完整,不再有缺失值了。
x_missing_reg=x_missing.copy()
#找出数据集中,缺失值从小到大排列的特征们的顺序,并且有了这些的索引
sortindex=np.argsort(x_missing_reg.isnull().sum(axis=0)).values
#np.argsort()返回的是从小到大排序的顺序所对应的索引
sortindex

返回缺失值多少的从小到大的数组

array([ 6, 12,  8,  7,  9,  0,  2,  1,  5,  4,  3, 10, 11], dtype=int64)
x_missing_reg.isnull().sum(axis=0)
0     200
1     201
2     200
3     203
4     202
5     201
6     185
7     197
8     196
9     197
10    204
11    214
12    189
dtype: int64
for i in sortindex:
    
    #构建我们的新特征矩阵和标签
    df=x_missing_reg
    fillc=df.iloc[:,i]
    df=pd.concat([df.iloc[:,df.columns!=i],pd.DataFrame(y_full)],axis=1)
    
    #在新的特征矩阵中,对含有缺失值的列,进行0的填充
    df_0=SimpleImputer(missing_values=np.nan,
                      strategy='constant',fill_value=0).fit_transform(df)
    
    #找出我们的训练集和测试集
    ytrain=fillc[fillc.notnull()]
    ytest=fillc[fillc.isnull()]
    xtrain=df_0[ytrain.index,:]
    xtest=df_0[ytest.index,:]
    
    #用随机森林回归填补缺失值
    rfc=RandomForestRegressor(n_estimators=100)
    rfc=rfc.fit(xtrain,ytrain)
    ypredict=rfc.predict(xtest)
    
    #将填补好的特征返回到我们的原始的特征矩阵中
    x_missing_reg.loc[x_missing_reg.iloc[:,i].isnull(),i] =ypredict

6.对填补好的数据进行建模

X=[x_full,x_missing_mean,x_missing_0,x_missing_reg]

mse=[]
std=[]

for x in X:
    estimator=RandomForestRegressor(random_state=0,n_estimators=100)
    scores=cross_val_score(estimator,x,y_full,scoring='neg_mean_squared_error',cv=5).mean()
    mse.append(scores*-1)
[*zip(["x_full","x_missing_mean","x_missing_0","x_missing_reg"],mse)]
[('x_full', 21.62860460743544),
 ('x_missing_mean', 40.84405476955929),
 ('x_missing_0', 49.50657028893417),
 ('x_missing_reg', 18.15993828660453)]

可以看出,用随机森林填补确实值的mse最小

7.用所得到的结果画出条形图

x_labels=['Full data',
          'Zero Imputation',
          'Mean Imputation',
          'Regressor Imputation']
colors=['r','g','b','orange']

plt.figure(figsize=(12,6))
ax=plt.subplot(111)
for i in np.arange(len(mse)):
    ax.barh(i,mse[i],color=colors[i],alpha=0.6,align='center')
ax.set_title('Imputation Techniques with Boston Data')
ax.set_xlim(left=np.min(mse) * 0.9,
             right=np.max(mse) * 1.1)#设置x轴取值范围
ax.set_yticks(np.arange(len(mse)))
ax.set_xlabel('MSE')
ax.set_yticklabels(x_labels)
plt.show()

sklearn专题二:随机森林_第5张图片

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

通过画学习曲线,或者网格搜索,我们能够探索到调参边缘(代价可能是训练一次模型要跑三天三夜),但是在现 实中,高手调参恐怕还是多依赖于经验,而这些经验,来源于: 1 )非常正确的调参思路和方法, 2)对模型评估指 标的理解, 3 )对数据的感觉和经验, 4 )用洪荒之力去不断地尝试。
我们也许无法学到高手们多年累积的经验,但我们可以学习他们对模型评估指标的理解和调参的思路。
那我们首先来讲讲正确的调参思路。模型调参,第一步是要找准目标:我们要做什么?一般来说,这个目标是提升某个模型评估指标,比如对于随机森林来说,我们想要提升的是模型在未知数据上的准确率(由 score或 oob_score_来衡量)。找准了这个目标,我们就需要思考:模型在未知数据上的准确率受什么因素影响?在机器学 习中,我们用来 衡量模型在未知数据上的准确率 的指标,叫做 泛化误差( Genelization error
泛化误差
当模型在未知数据(测试集或者袋外数据)上表现糟糕时,我们说模型的泛化程度不够,泛化误差大,模型的效果 不好。泛化误差受到模型的结构(复杂度)影响。看下面这张图,它准确地描绘了泛化误差与模型复杂度的关系, 当模型太复杂,模型就会过拟合,泛化能力就不够,所以泛化误差大。当模型太简单,模型就会欠拟合,拟合能力 就不够,所以误差也会大。只有当模型的复杂度刚刚好的才能够达到泛化误差最小的目标。
sklearn专题二:随机森林_第6张图片
那模型的复杂度与我们的参数有什么关系呢?对树模型来说,树越茂盛,深度越深,枝叶越多,模型就越复杂。所 以树模型是天生位于图的右上角的模型,随机森林是以树模型为基础,所以随机森林也是天生复杂度高的模型。随 机森林的参数,都是向着一个目标去:减少模型的复杂度,把模型往图像的左边移动,防止过拟合。当然了,调参 没有绝对,也有天生处于图像左边的随机森林,所以调参之前,我们要先判断,模型现在究竟处于图像的哪一边。
泛化误差的背后其实是 偏差 - 方差困境 ”,原理十分复杂,无论你翻开哪一本书,你都会看见长篇的数学论证和每个 字都能看懂但是连在一起就看不懂的文字解释。在下一节偏差 vs方差中,我用最简单易懂的语言为大家解释了泛化 误差背后的原理,大家选读。那我们只需要记住这四点:
1 )模型太复杂或者太简单,都会让泛化误差高,我们追求的是位于中间的平衡点
2 )模型太复杂就会过拟合,模型太简单就会欠拟合
3 )对树模型和树的集成模型来说,树的深度越深,枝叶越多,模型越复杂
4 )树模型和树的集成模型的目标,都是减少模型复杂度,把模型往图像的左边移动
那具体每个参数,都如何影响我们的复杂度和模型呢?我们一直以来调参,都是在学习曲线上轮流找最优值,盼望 能够将准确率修正到一个比较高的水平。然而我们现在了解了随机森林的调参方向:降低复杂度,我们就可以将那 些对复杂度影响巨大的参数挑选出来,研究他们的单调性,然后专注调整那些能最大限度让复杂度降低的参数。对 于那些不单调的参数,或者反而会让复杂度升高的参数,我们就视情况使用,大多时候甚至可以退避。基于经验,我对各个参数对模型的影响程度做了一个排序。在我们调参的时候,大家可以参考这个顺序。

参数

对模型在未知数据上的评估性能的影响

影响程度

n_estimators

提升至平稳,n_estimators,不影响单个模型的复杂度

⭐⭐⭐⭐

max_depth

有增有减,默认最大深度,即最高复杂度,向复杂度降低的方向调参

max_depth,模型更简单,且向图像的左边移动

⭐⭐⭐

min_samples

_leaf

有增有减,默认最小限制1,即最高复杂度,向复杂度降低的方向调参

min_samples_leaf,模型更简单,且向图像的左边移动

⭐⭐

min_samples

_split

有增有减,默认最小限制2,即最高复杂度,向复杂度降低的方向调参

min_samples_split,模型更简单,且向图像的左边移动

⭐⭐

max_features

有增有减,默认auto,是特征总数的开平方,位于中间复杂度,既可以 向复杂度升高的方向,也可以向复杂度降低的方向调参max_features, 模 型 更 简 单 , 图 像 左 移         max_features,模型更复杂,图像右移

max_features是唯的,既能够让型更也能够让型更复杂,所以在调整这个参数时候需要们调参方向

criterion

有增有减,一般使用gini

看具体情况

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

基于方差和偏差的调参方法,在乳腺癌数据上进行一次随  机森林的调参。乳腺癌数据是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  #(569, 30)
data.target  #返回一个2分类集

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

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

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

score_pre

输出结果:0.9648809523809524

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

选择学习曲线来查看n_estimators的趋势

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中的索引

sklearn专题二:随机森林_第7张图片

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

scorel = []
for i in range(65,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),([*range(65,75)][scorel.index(max(scorel))])) 
plt.figure(figsize=[20,5])
plt.plot(range(65,75),scorel) 
plt.show()

sklearn专题二:随机森林_第8张图片

 

调整n_estimators的效果显著,模型的准确率立刻上升了0.003。接下来就进入网格搜索,我们将使用网格搜索对参数一个个进行调整。为什么我们不同时调整多个参数呢?原因有两个:

1)同时调整多个参数会运行非常缓慢,  在课堂上我们没有这么多的时间。

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

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.

#调整max_depth

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

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

rfc = RandomForestClassifier(n_estimators=73  #前面的学习曲线确定的
                             ,random_state=90
                             )
GS = GridSearchCV(rfc,param_grid,cv=10) 
GS.fit(data.data,data.target)

GS.best_params_


GS.best_score_
输出没变化:0.9666353383458647

8.调整max_features

#调整max_features

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

"""

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

"""


rfc = RandomForestClassifier(n_estimators=73
                             ,random_state=90
                             )
GS = GridSearchCV(rfc,param_grid,cv=10) 
GS.fit(data.data,data.target)

GS.best_params_

GS.best_score_

输出值:0.9666666666666668 提高了

GS.best_params_  输出结果为:{'max_features': 24}

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=73
                             ,random_state=90
                             ,max_features=24
                             )
GS = GridSearchCV(rfc,param_grid,cv=10) 
GS.fit(data.data,data.target)

GS.best_params_

GS.best_score_

输出值:0.9666666666666668保持不变了

10.不懈努力,继续尝试min_samples_split

# 调 整 min_samples_split 
param_grid={'min_samples_split':np.arange(2,2+20,1)}

rfc = RandomForestClassifier(n_estimators=73
                             ,random_state=90
                             ,max_features=24
                             )
GS = GridSearchCV(rfc,param_grid,cv=10) 
GS.fit(data.data,data.target)

GS.best_params_
GS.best_score_

输出值:9701754385964912  提高了

GS.best_params_  输出结果{'min_samples_split': 6}

sklearn专题二:随机森林_第9张图片

限制min_samples_split ,是让模型变得简单,把模型向左推,而模型整体的准确率下降了,即整体的泛化误差上升了,这说明模型现在位于图像左边,即泛化误差最低点的左边(偏差为主导的一边)。通常来说,随机森林应该在泛化误差最低点的右边,树模型应该倾向于过拟合,而不是拟合不足。

11.最后尝试一下criterion

#调整Criterion

param_grid = {'criterion':['gini', 'entropy']}


rfc = RandomForestClassifier(n_estimators=73
                             ,random_state=90
                             ,max_features=24
                             ,min_samples_split=6
                            )
GS = GridSearchCV(rfc,param_grid,cv=10) 
GS.fit(data.data,data.target)

GS.best_params_
GS.best_score_

输出值:0.9701754385964912  没有变化

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

rfc = RandomForestClassifier(n_estimators=73
                             ,random_state=90
                             ,max_features=24
                             ,min_samples_split=6
                            )

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

score - score_pre #得出差值

整体提高了0.005294486215538852

在整个调参过程之中:

1.学习曲线调整n_estimators,先10个一组,再细分,确定n_estimators=73最优

2.调整max_depth,得分没有变化,我们可以选择不调整此参数

3.调整max_features,得分提高了,max_features取值24

4.调整min_samples_leaf,得分没有变化,我们可以选择不调整此参数

5.调整min_samples_split,得分提高了,min_samples_split取值6

6.最后尝试一下criterion,得分没有变化,我们可以选择不调整此参数

你可能感兴趣的:(sklearn,随机森林,机器学习)