随机森林
1 概述
1.1 集成算法概述
集成学习(ensemble learning)是时下非常流行的机器学习算法,它本身不是一个单独的机器学习算法,而是通过在数据上构建多个模型,集成所有模型的建模结果。基本上所有的机器学习领域都可以看到集成学习的身影,在现实中集成学习也有相当大的作用,它可以用来做市场营销模拟的建模,统计客户来源,保留和流失,也可用来预测疾病的风险和病患者的易感性。在现在的各种算法竞赛中,随机森林,梯度提升树(GBDT),Xgboost等集成算法的身影也随处可见,可见其效果之好,应用之广。
集成算法的目标 |
集成算法会考虑多个评估器的建模结果,汇总之后得到一个综合的结果,以此来获取比单个模型更好的回归或 分类表现。 |
多个模型集成成为的模型叫做集成评估器(ensemble estimator),组成集成评估器的每个模型都叫做基评估器(base estimator)(对随机森林来说,基评估器就是决策树)。通常来说,有三类集成算法:装袋法(Bagging),提升法(Boosting)和stacking。
装袋法:核心思想是构建多个相互独立的评估器,然后对其预测进行平均或多数表决原则来决定集成评估器的结果。装袋法的代表模型就是随机森林。(采样n次,建n个模型,互不影响,例:随机森林中每棵树都是互相独立的)
提升法:基评估器是相关的,是按顺序一一构建的。其核心思想是结合弱评估器的力量一次次对难以评估的样本进行预测,从而构成一个强评估器。提升法的代表模型有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 |
用于不合适估算器的软投票/多数规则分类器 |
集成算法中,有一半以上都是树的集成模型,可以想见决策树在集成中必定是有很好的效果。在这堂课中,我们会以随机森林为例,慢慢为大家揭开集成算法的神秘面纱。
· 复习:sklearn中的决策树
在开始随机森林之前,我们先复习一下决策树。决策树是一种原理简单,应用广泛的模型,它可以同时被用于分类和回归问题。决策树的主要功能是从一张有特征和标签的表格中,通过对特定特征进行提问,为我们总结出一系列决策规则(对样本分类),并用树状图来呈现这些决策规则。
(例如图中体温是否恒温为特征,哺乳动物为标签)
决策树的核心问题有两个:
一:是如何找出正确的特征来进行提问,即如何分枝
二:树生长到什么时候应该停下。
对于第一个问题,我们定义了用来衡量分枝质量的指标不纯度,分类树的不纯度用基尼系数或信息熵来衡量,回归树的不纯度用MSE均方误差来衡量。每次分枝时,决策树对所有的特征进行不纯度计算,选取不纯度最低的特征进行分枝,分枝后,又再对被分枝的不同取值下,计算每个特征的不纯度,继续选取不纯度最低的特征进行分枝。
每分枝一层,树整体的不纯度会越来越小,决策树追求的是最小不纯度。因此,决策树会一致分枝,直到没有更多的特征可用,或整体的不纯度指标已经最优,决策树就会停止生长。
决策树非常容易过拟合,这是说,它很容易在训练集上表现优秀,却在测试集上表现很糟糕。为了防止决策树的过拟合,我们要对决策树进行剪枝,sklearn中提供了大量的剪枝参数,
2 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,随机森林分类器。
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.导入我们需要的包
#导入我们需要的包 #画图的时候,需要这个环境,将这个jupyter导入到这个环境 %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建模的基本流程
#1.实例化 #2.训练集带入实例化后的模型去进行训练,使用的接口是fit #3.使用其他接口将测试集导入我们训练好的模型去获取我们希望获取的结果(score,Y_test) #导入划分训练集和测试集的类 from sklearn.model_selection import train_test_split #test_size=0.3 即70%做训练集,30%测试集(训练集和测试集随机划分导致结果不同) Xtrain,Xtest,Ytrain,Ytest = train_test_split(wine.data,wine.target,test_size=0.3) #1.实例化 clf = DecisionTreeClassifier(random_state=0) #实例化随机森林 rfc = RandomForestClassifier(random_state=0) #2.训练数据 clf = clf.fit(Xtrain,Ytrain) rfc = rfc.fit(Xtrain,Ytrain) #3.测试 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.8703703703703703 Random Forest:0.9629629629629629 |
4.画出随机森林和决策树在一组交叉验证下的效果对比
#交叉验证:cross_val_score #(分训练集和测试集时,不同的分法会对模型结果产生影响),探讨不同的训练集和测试集中,模型的稳定性 #将数据集划分为n分,依次取每一份做测试集,每n-1份做训练集,多次训练模型以观测模型稳定性的方法 from sklearn.model_selection import cross_val_score import matplotlib.pyplot as plt #实例化随机森林(森林中数目的数量=25) 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) #交叉验证的次数10次 plt.plot(range(1,11),rfc_s,label="RandomForest") plt.plot(range(1,11),clf_s,label="DecisionTree") #显示图例 plt.legend() plt.show() #====================一种更加有趣也更简单的写法===================# """ 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" """ |
可以看出总的来说随机森林效果好于决策树
5.画出随机森林和决策树在十组交叉验证下的效果对比
#保存验证结果 rfc_1 = [] clf_1 = [] #进行10次建模,总共100次验证 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() |
进一步体现出随机森林的效果比决策树好,且两条曲线走势相同,即决策树效果越好,随机森林效果也越好
6.n_estimators的学习曲线
#####【TIME WARNING: 2mins 30 seconds】##### superpa = [] for i in range(200): #n_estimators=i+1从建1棵到200棵,跑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) #找出准确率最高的n_estimators,list.index(object)返回对象object在列表list中的索引 print(max(superpa),superpa.index(max(superpa))) plt.figure(figsize=[20,5]) plt.plot(range(1,201),superpa) plt.show() |
结果:0.9944444444444445 12
可以看出随着n_estimators的增长,效果越来越好,但当达到一定数量时,随机森林的精确性不再上升或波动
思考
随机森林用了什么方法,来保证集成的效果一定好于单个分类器?
2.1.3 random_state
随机森林的本质是一种装袋集成算法(bagging),装袋集成算法是对基评估器的预测结果进行平均或用多数表决原则来决定集成评估器的结果。在刚才的红酒例子中,我们建立了25棵树,对任何一个样本而言,平均或多数表决原则下,当且仅当有13棵以上的树判断错误的时候,随机森林才会判断错误。单独一棵决策树对红酒数据集的分类准确率在0.85上下浮动,假设一棵树判断错误的可能性为0.2(ε),那20棵树以上都判断错误的可能性是:
其中,i是判断错误的次数,也是判错的树的数量,ε是一棵树判断错误的概率,(1-ε)是判断正确的概率,共判对25-i次。采用组合,是因为25棵树中,有任意i棵都判断错误。
import numpy as np from scipy.special import comb #假设一棵树判断错误的概率0.2 np.array([comb(25,i)*(0.2**i)*((1-0.2)**(25-i)) for i in range(13,26)]).sum() -->0.00036904803455582827 |
可见,判断错误的几率非常小,这让随机森林在红酒数据集上的表现远远好于单棵决策树。
那现在就有一个问题了:我们说袋装法服从多数表决原则或对基分类器结果求平均,这即是说,我们默认森林中的每棵树应该是不同的,并且会返回不同的结果。设想一下,如果随机森林里所有的树的判断结果都一致(全判断对 或全判断错),那随机森林无论应用何种集成原则来求结果,都应该无法比单棵决策树取得更好的效果才对。但我们使用了一样的类DecisionTreeClassifier,一样的参数,一样的训练集和测试集,为什么随机森林里的众多树会有不同的判断结果?