随机森林在 sklearn 中的实现

2019-03-18 10:56:39 +08:00
 yoggieCDA

小伙伴们大家好~o( ̄▽ ̄)ブ,我是菜菜,我的开发环境是Jupyter lab,所用的库和版本大家参考:

Python 3.7.1 (你的版本至少要 3.4 以上

Scikit-learn 0.20.0 (你的版本至少要 0.19

Numpy 1.15.3, Pandas 0.23.4, Matplotlib 3.0.1, SciPy 1.1.0

1 概述

1.1 集成算法概述

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

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

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

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

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

1.2 sklearn 中的集成算法

| 类 | 类的功能 | | ----------------------------------- | --------------------------------------- | | 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 | 用于不合适估算器的软投票 /多数规则分类器 |

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

在开始随机森林之前,我们先复习一下决策树。决策树是一种原理简单,应用广泛的模型,它可以同时被用于分类和回归问题。决策树的主要功能是从一张有特征和标签的表格中,通过对特定特征进行提问,为我们总结出一系列决策规则,并用树状图来呈现这些决策规则。

决策树的核心问题有两个,一个是如何找出正确的特征来进行提问,即如何分枝,二是树生长到什么时候应该停下。

对于第一个问题,我们定义了用来衡量分枝质量的指标不纯度,分类树的不纯度用基尼系数或信息熵来衡量,回归树的不纯度用 MSE 均方误差来衡量。每次分枝时,决策树对所有的特征进行不纯度计算,选取不纯度最低的特征进行分枝,分枝后,又再对被分枝的不同取值下,计算每个特征的不纯度,继续选取不纯度最低的特征进行分枝。

每分枝一层,树整体的不纯度会越来越小,决策树追求的是最小不纯度。因此,决策树会一致分枝,直到没有更多的特征可用,或整体的不纯度指标已经最优,决策树就会停止生长。

决策树非常容易过拟合,这是说,它很容易在训练集上表现优秀,却在测试集上表现很糟糕。为了防止决策树的过拟合,我们要对决策树进行剪枝,sklearn 中提供了大量的剪枝参数,我们一会儿会带大家复习一下。

我们先来了解一下 sklearn 建模的基本流程。

在这个流程下,随机森林对应的代码和决策树基本一致:

from sklearn.tree import RandomForestClassifier		#导入需要的模块

rfc = RandomForestClassifier()     					#实例化
rfc = rfc.fit(X_train,y_train)						#用训练集数据训练模型
result = rfc.score(X_test,y_test)					#导入测试集,从接口中调用需要的信息

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. 导入我们需要的包
%matplotlib inline
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine
  1. 导入需要的数据集
wine = load_wine()

wine.data
wine.target
  1. 复习:sklearn 建模的基本流程
from sklearn.model_selection import train_test_split

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)
     )
  1. 画出随机森林和决策树在十组交叉验证下的效果对比
#带大家复习一下交叉验证
#交叉验证:是数据集划分为 n 分,依次取每一份做测试集,每 n-1 份做训练集,多次训练模型以观测模型稳定性的方法

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

#是否有注意到,单个决策树的波动轨迹和随机森林一致?
#再次验证了我们之前提到的,单个决策树的准确率越高,随机森林的准确率也会越高
  1. 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)))
plt.figure(figsize=[20,5])
plt.plot(range(1,201),superpa)
plt.show()

| 思考 | | ---------------------------------------------------------- | | 随机森林用了什么方法,来保证集成的效果一定好于单个分类器? |

2.2 重要属性和接口

随机森林中有三个非常重要的属性:.estimators_,.oob_score_以及.feature_importances_

.estimators_是用来查看随机森林中所有树的列表的。

oob_score_指的是袋外得分。随机森林为了确保林中的每棵树都不尽相同,所以采用了对训练集进行有放回抽样的方式来不断组成信的训练集,在这个过程中,会有一些数据从来没有被随机挑选到,他们就被叫做“袋外数据”。这些袋外数据,没有被模型用来进行训练,sklearn 可以帮助我们用他们来测试模型,测试的结果就由这个属性 oob_score_来导出,本质还是模型的精确度。

而.feature_importances_和决策树中的.feature_importances_用法和含义都一致,是返回特征的重要性。

随机森林的接口与决策树完全一致,因此依然有四个常用接口:apply, fit, predictscore。除此之外,还需要注意随机森林的 predict_proba 接口,这个接口返回每个测试样本对应的被分到每一类标签的概率,标签有几个分类就返回几个概率。如果是二分类问题,则 predict_proba 返回的数值大于 0.5 的,被分为 1,小于 0.5 的,被分为 0。传统的随机森林是利用袋装法中的规则,平均或少数服从多数来决定集成的结果,而 sklearn 中的随机森林是平均每个样本对应的 predict_proba 返回的概率,得到一个平均概率,从而决定测试样本的分类。

#大家可以分别取尝试一下这些属性和接口

rfc = RandomForestClassifier(n_estimators=25)
rfc = rfc.fit(Xtrain, Ytrain)
rfc.score(Xtest,Ytest)

rfc.feature_importances_
rfc.apply(Xtest)
rfc.predict(Xtest)
rfc.predict_proba(Xtest)

掌握了上面的知识,基本上要实现随机森林分类已经是没问题了。从红酒数据集的表现上来看,随机森林的效用比单纯的决策树要强上不少,大家可以自己更换其他数据来试试看(比如前面内容提到的完整课案例中的泰坦尼克号数据)。

2197 次点击
所在节点   科技
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/545683

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX