机器学习分类算法之随机森林(集成学习算法)

Posted 王小王-123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了机器学习分类算法之随机森林(集成学习算法)相关的知识,希望对你有一定的参考价值。

目录

什么是集成学习?

随机森林

随机森林的生成算法

 随机森林的随机性

随机森林的优势

随机森林的参数详解

随机森林模型提高方法

最大特征数(max_features)

子树的数量(n_estimators)最重要的

最大深度(max_depth)

内部节点再划分所需最小样本数(min_samples_split)

叶子节点最少样本数(min_samples_leaf)

叶子节点最小的样本权重(min_weight_fraction_leaf)

最大叶子节点数(max_leaf_nodes)

节点划分最小不纯度(min_impurity_split)

用于拟合和预测的并行运行的工作数量(n_jobs)

随机数生成器(random_state)

如何调参

代码实现

案例代码

n_estimators调参(学习曲线)

优化max_depth

调整min_samples_leaf

 min_samples_split优化

调整max_features及其他参数

网格搜索(电脑性能强)

随机森林做特征筛选(可视化)

最佳模型代码

每文一语


 👇👇🧐🧐✨✨🎉🎉

欢迎点击专栏其他文章(欢迎订阅·持续更新中~)

机器学习之Python开源教程——专栏介绍及理论知识概述

机器学习框架及评估指标详解

Python监督学习之分类算法的概述

数据预处理之数据清理,数据集成,数据规约,数据变化和离散化

特征工程之One-Hot编码、label-encoding、自定义编码

卡方分箱、KS分箱、最优IV分箱、树结构分箱、自定义分箱

特征选取之单变量统计、基于模型选择、迭代选择

机器学习分类算法之朴素贝叶斯

【万字详解·附代码】机器学习分类算法之K近邻(KNN)

《全网最强》详解机器学习分类算法之决策树(附可视化和代码)

机器学习分类算法之支持向量机

机器学习分类算法之Logistic 回归(逻辑回归)

持续更新中~

作者简介

博客名:王小王-123

简介:CSDN博客专家、CSDN签约作者、华为云享专家,腾讯云、阿里云、简书、InfoQ创作者。公众号:书剧可诗画,2020年度CSDN优秀创作者。左手诗情画意,右手代码人生,欢迎一起探讨技术的诗情画意!


什么是集成学习?

定义:本身并不是一个单独的机器学习算法,而是通过构建并结合多个机器学习器来完成学习任务,以达到获得比单个学习器更好的学习效果的一种机器学习方法。高端点的说叫“博彩众长”,庸俗的说叫“三个臭皮匠,顶个诸葛亮”。

思路:在对新的实例进行分类的时候,把若干个单个分类器集成起来,通过对多个分类器的分类结果进行某种组合来决定最终的分类,以取得比单个分类器更好的性能。如果把单个分类器比作一个决策者的话,集成学习的方法就相当于多个决策者共同进行一项决策。

原理:生成一组个体学习器,然后采用某种策略将他们结合起来。个体学习器可以由不同的学习算法生成,之间也可以按照不同的规律生成。

就像上图所示

集成(ensemble)是合并多个机器学习模型来构建更强大模型的方法。在机器学习文献中有许多模型都属于这一类,但已证明有两种集成模型对大量分类和回归的数据集都是有效的,二者都以决策树为基础,分别是随机森林(random forest)和梯度提升决策树(gradient boosted decision tree)

随机森林

决策树的一个主要缺点在于经常对训练数据过拟合随机森林是解决这个问题的一种方法。随机森林本质上是许多决策树的集合,其中每棵树都和其他树略有不同。随机森林背后的思想是,每棵树的预测可能都相对较好,但可能对部分数据过拟合。如果构造很多树,并且每棵树的预测都很好,但都以不同的方式过拟合,那么我们可以对这些树的结果取平均值来降低过拟合。既能减少过拟合又能保持树的预测能力,这可以在数学上严格证明。
为了实现这一策略,我们需要构造许多决策树。每棵树都应该对目标值做出可以接受的预
测,还应该与其他树不同。随机森林的名字来自于将随机性添加到树的构造过程中,以确
保每棵树都各不相同。随机森林中树的随机化方法有两种:一种是通过选择用于构造树的
数据点,另一种是通过选择每次划分测试的特征。

想 要 构 造 一 个 随 机 森 林 模 型, 你 需 要 确 定 用 于 构 造 的 树 的 个 数
(RandomForestRegressor 或 RandomForestClassifier 的 n_estimators 参数)。比如我们想要构造 10 棵树。

这些树在构造时彼此完全独立,算法对每棵树进行不同的随机选择,以确保树和树之间是有区别的。想要构造一棵树,首先要对数据进行自助采样(bootstrapsample)。也就是说,从 n_samples 个数据点中有放回地(即同一样本可以被多次抽取)重复随机抽取一个样本,共抽取 n_samples 次。这样会创建一个与原数据集大小相同的数据集,但有些数据点会缺失(大约三分之一),有些会重复。

举例说明:

比如我们想要创建列表 ['a', 'b', 'c', 'd'] 的自助采样。一种可能的自主采样是 ['b', 'd', 'd', 'c'],另一种可能的采样为 ['d', 'a', 'd', 'a']。

接下来,基于这个新创建的数据集来构造决策树。但是,要对我们在介绍决策树时描述的算法稍作修改。在每个结点处,算法随机选择特征的一个子集,并对其中一个特征寻找最佳测试,而不是对每个结点都寻找最佳测试。选择的特征个数由 max_features 参数来控制。每个结点中特征子集的选择是相互独立的,这样树的每个结点可以使用特征的不同子集来做出决策。

由于使用了自助采样,随机森林中构造每棵决策树的数据集都是略有不同的。由于每个结点的特征选择,每棵树中的每次划分都是基于特征的不同子集。这两种方法共同保证随机森林中所有树都不相同。

在这个过程中的一个关键参数是 max_features。如果我们设置 max_features 等于n_features那么每次划分都要考虑数据集的所有特征,在特征选择的过程中没有添加随机性(不过自助采样依然存在随机性)。如果设置 max_features 等于 1,那么在划分时将无法选择对哪个特征进行测试,只能对随机选择的某个特征搜索不同的阈值。

因此,如果 max_features 较大,那么随机森林中的树将会十分相似,利用最独特的特征可以轻松拟合数据。如果 max_features 较小,那么随机森林中的树将会差异很大,为了很好地拟合数据,每棵树的深度都要很大。

随机森林的生成算法

1.从样本集中通过重采样的方式产生n个样本
2.假设样本特征数目为a,对n个样本选择a中的k个特征,用建立决策树的方式获得最佳分割点
3.重复m次,产生m棵决策树
4.多数投票机制来进行预测
(需要注意的一点是,这里m是指循环的次数,n是指样本的数目,n个样本构成训练的样本集,而m次循环中又会产生m个这样的样本集)

 随机森林的随机性

集合中的每一棵树都是从训练集替换出来的样本中构建的。在树构建期间分割节点时,所选择的分割不再是所有特征之间最好的分割。相反,被选中的分割是特征的随机子集之间最好的分割。由于随机性,森林的偏向通常略有增加。但是,由于平均值,它的方差也减小,从而产生一个整体更好的模型

随机森林的优势

随机森林算法几乎不需要输入的准备。它们不需要测算就能够处理二分特征、分类特征、数值特征的数据。随机森林算法能完成隐含特征的选择,并且提供一个很好的特征重要度的选择指标。
随机森林算法训练速度快。性能优化过程刚好又提高了模型的准确性

通用性:随机森林可以应用于很多类别的模型任务。它们可以很好的处理回归问题,也能对分类问题应付自如(甚至可以产生合适的标准概率值),它们还可以用于聚类分析问题。
简洁性:对于随机森林来说,如果不是结论模型很简洁,就是学习算法本身很简洁。基本的随机森林学习算法仅用几行代码就可以写出来了。

1. 由于采用了集成算法,本身精度比大多数单个算法要好,所以准确性高。
2. 在测试集上表现良好,由于两个随机性的引入,使得随机森林不容易陷入过拟合(样本随机,特征随机)。
3. 在工业上,由于两个随机性的引入,使得随机森林具有一定的抗噪声能力,对比其他算法具有一定优势。
4. 由于树的组合,使得随机森林可以处理非线性数据,本身属于非线性分类(拟合)模型。
5. 它能够处理很高维度(feature很多)的数据,并且不用做特征选择,对数据集的适应能力强:既能处理离散型数据,也能处理连续型数据,数据集无需规范化。
6. 训练速度快,可以运用在大规模数据集上。
7. 可以处理缺省值(单独作为一类),不用额外处理。
8. 由于有袋外数据(OOB),可以在模型生成过程中取得真实误差的无偏估计,且不损失训练数据量。
9. 在训练过程中,能够检测到feature间的互相影响,且可以得出feature的重要性,具有一定参考意义。(可以做特征筛选)用于其他模型的输入
10. 由于每棵树可以独立、同时生成,容易做成并行化方法。
11. 由于实现简单、精度高、抗过拟合能力强,当面对非线性数据时,适于作为基准模型。

随机森林的参数详解

随机森林主要的参数有n_estimators(子树的数量)、max_depth(树的最大生长深度)、min_samples_leaf(叶子的最小样本数量)、min_samples_split(分支节点的最小样本数量)、max_features(最大选择特征数)。它们对随机森林模型复杂度的影响如下图所示:

 可以看到,n_estimators是影响程度最大的参数,下面我们会对上面的参数自定义调优,前面我们都知道有一个很强大的模块就是网格调参,但是在实际的调优中,一般不直接一上手就暴力搜索,可以测试一下参数迭代和探索学习曲线,最终确定参数的最优

随机森林模型提高方法

1.特征选择
1)输入特征按照其重要性从高到底排序,其中特征重要性排序可以根据与输出变量的皮尔森相关系数或者由支持向量机模型得出;(有时候不适用
2)去除与输出变量相关性很小的特征;(有时候不适用
3)在原有特征的基础上,添加新的特征,新特征可以是原有特征集的组合或划分,例如将year按season划分,将weekend和holiday组合为restday(见具体情况

在随机森林中,特征选取除非是那种特别不相关的变量,需要筛选出去,一般只要有先验知识,觉得这些变量都是有点意思的,那么最好不要删除,因为在随机森林的内部算法里面,可能一环扣一环,删除之后反而对模型的效果有所影响。

2.参数优化(最佳的选择)
以python的sklearn.ensemble.RandomForestRegressor库为例,主要需要调节的参数为:
1)n_estimators:表示树的数量,通常随着树的数量的增加,test error会逐渐减小,当到达一定数目时,test error的变化变得很小,继续增大则test error反而会变大,出现过拟合现象,这时候就可以确定较为合理的树的数量;n_estimators的选择可通过GridSearchCV得到最优test error对应的树的数量,也可以通过学习曲线得出,再去不断寻找
2)max_features:表示基决策树的每个节点随机选择的最大特征数,传统决策树模型在选择特征时考虑所有可能的特征,而它降低了单个树的多样性,而由于随机森林基于集成学习思想的优点,减小max_features不仅会提升算法速度,也有可能降低测试误差,这也是RF模型在Bagging集成学习方法基础上的一个改进;对max_features的选择是逐一尝试,直到找到比较理想的值

最大特征数(max_features)

Auto/None :简单地选取所有特征,每颗树都可以利用他们。这种情况下,每颗树都没有任何的限制。

sqrt :此选项是每颗子树可以利用总特征数的平方根个。

例如,如果变量(特征)的总数是100,所以每颗子树只能取其中的10个;“log2”是另一种相似类型的选项。

0.2:此选项允许每个随机森林的子树可以利用变量(特征)数的20%。如果想考察的特征x%的作用, 我们可以使用“0.X”的格式。

max_features如何影响性能和速度?

增加max_features一般能提高模型的性能,因为在每个节点上,我们有更多的选择可以考虑。

然而,这未必完全是对的,因为它降低了单个树的多样性,而这正是随机森林独特的优点。 但是,可以肯定,你通过增加max_features会降低算法的速度。 因此,你需要适当的平衡和选择最佳max_features。

子树的数量(n_estimators)最重要的

在利用最大投票数或平均值来预测之前,你想要建立子树的数量。 较多的子树可以让模型有更好的性能,但同时让你的代码变慢。 你应该选择尽可能高的值,只要你的处理器能够承受的住,因为这使你的预测更好更稳定。

最大深度(max_depth)

默认可以不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间。(int表示深度,None表示树会生长到所有叶子都分到一个类,或者某节点所代表的样本已小于min_samples_split)

内部节点再划分所需最小样本数(min_samples_split)

这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择最优特征来进行划分。 默认是2.如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。(int表示样本数,2表示默认值)

叶子节点最少样本数(min_samples_leaf)

这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝。 默认是1,可以输入最少的样本数的整数,或者最少样本数占样本总数的百分比。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。

叶子节点最小的样本权重(min_weight_fraction_leaf)

这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝。 默认是0,就是不考虑权重问题。一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了。

最大叶子节点数(max_leaf_nodes)

通过限制最大叶子节点数,可以防止过拟合,默认是"None”,即不限制最大的叶子节点数。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值,但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。

节点划分最小不纯度(min_impurity_split)

这个值限制了决策树的增长,如果某节点的不纯度(基于基尼系数,均方差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。一般不推荐改动默认值1e-7。

用于拟合和预测的并行运行的工作数量(n_jobs)

一般取整数,可选的(默认值为1),如果为-1,那么工作数量被设置为核的数量,机器上所有的核都会被使用(跟CPU核数一致)。如果n_jobs=k,则计算被划分为k个job,并运行在K核上。注意,由于进程间通信的开销,加速效果并不会是线性的(job数K不会提示K倍)通过构建大量的树,比起单颗树所需要的时间,性能也能得到很大的提升

随机数生成器(random_state)

随机数生成器使用的种子,如果是RandomState实例,则random_stats就是随机数生成器;如果为None,则随机数生成器是np.random使用的RandomState实例。

上面决策树参数中最重要的包括子树的数量n_estimators,最大特征数max_features, 最大深度max_depth, 内部节点再划分所需最小样本数min_samples_split和叶子节点最少样本数min_samples_leaf

如何调参

对于随机森林如何调参,这里给出一些好的建议,如果你是网格搜索,而且是那种毫无规则的网格搜索,那么模型跑个三天三夜也未必有结果,此外,你的机器可能没有这么好的配置,根本跑不动!

在下图中,我们可以看到这些参数对Random Forest整体模型性能的影响:

① 基于泛化误差与模型复杂度的关系来进行调参;

② 根据对模型的影响程度,由大到小对参数排序,并确定哪些参数会使模型复杂度减小,哪些会增大;

③ 依次选择合适的参数,通过绘制学习曲线或网格搜索的方法调参,直到找到最大准确得分。

讲了做这么多的干货,下面上点实际的,代码整起

代码实现

案例代码

导入第三方库

#导入所需要的包
from sklearn.metrics import precision_score
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import classification_report#评估报告
from sklearn.model_selection import cross_val_score #交叉验证
from sklearn.model_selection import GridSearchCV #网格搜索
import matplotlib.pyplot as plt#可视化
import seaborn as sns#绘图包
from sklearn.preprocessing import StandardScaler,MinMaxScaler,MaxAbsScaler#归一化,标准化
# 忽略警告
import warnings
warnings.filterwarnings("ignore")

计算皮尔逊系数,并绘制热力相关图

X_valus=df.corr()[["n23"]].sort_values(by="n23",ascending=False).iloc[1:]
X_valus

这里查看相关系数

figure, ax = plt.subplots(figsize=(20, 20))
sns.heatmap(df.corr(), square=True, annot=True, ax=ax)
plt.show()

不加入任何的参数,直接原生态的随机森林,效果还是不错的

model=RandomForestClassifier()
# 训练模型
model.fit(X_train,y_train)
# 预测值
y_pred = model.predict(X_test)

'''
评估指标
'''
# 求出预测和真实一样的数目
true = np.sum(y_pred == y_test )
print('预测对的结果数目为:', true)
print('预测错的的结果数目为:', y_test.shape[0]-true)
# 评估指标
from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score,cohen_kappa_score
print('预测数据的准确率为: :.4%'.format(accuracy_score(y_test,y_pred)*100))
print('预测数据的精确率为::.4%'.format(
      precision_score(y_test,y_pred)*100))
print('预测数据的召回率为::.4%'.format(
      recall_score(y_test,y_pred)*100))
# print("训练数据的F1值为:", f1score_train)
print('预测数据的F1值为:',
      f1_score(y_test,y_pred))
print('预测数据的Cohen’s Kappa系数为:',
      cohen_kappa_score(y_test,y_pred))
# 打印分类报告
print('预测数据的分类报告为:','\\n',
      classification_report(y_test,y_pred))

n_estimators调参(学习曲线)

scorel = []
for i in range(0,200,10):
    model = RandomForestClassifier(n_estimators=i+1,
                                 n_jobs=-1,
                                 random_state=90).fit(X_train,y_train)
    score = model.score(X_test,y_test)
    scorel.append(score)

print(max(scorel),(scorel.index(max(scorel))*10)+1)  #作图反映出准确度随着估计器数量的变化,51的附近最好
plt.figure(figsize=[20,5])
plt.plot(range(1,201,10),scorel)
plt.show()

 确定了大致的范围,那么我们就可以在这个基础上缩小范围,迭代看看

## 根据上面的显示最优点在51附近,进一步细化学习曲线
scorel = []
for i in range(40,60):
    RFC = RandomForestClassifier(n_estimators=i,
                                 n_jobs=-1,
                                 random_state=90).fit(X_train,y_train)
    score = RFC.score(X_test,y_test)
    scorel.append(score)

print(max(scorel),([*range(40,60)][scorel.index(max(scorel))]))  #112是最优的估计器数量 #最优得分是0.98945
plt.figure(figsize=[20,5])
plt.plot(range(40,60),scorel) 
plt.show()

虽然给出的最佳是45,但是我依然会选择51,因为在接近某一个数字,它就是平稳的,效果肯定要好,并且模型的扰动性较好

优化max_depth

## 优化max_depth
scorel = []
for i in range(3,30):
    RFC = RandomForestClassifier(max_depth=i,n_estimators=51,
                                 n_jobs=-1,
                                 random_state=90).fit(X_train,y_train)
    score = RFC.score(X_test,y_test)
    scorel.append(score)

print(max(scorel),([*range(3,30)][scorel.index(max(scorel))]))  #112是最优的估计器数量 #最优得分是0.951462
plt.figure(figsize=[20,5])
plt.plot(range(3,30),scorel) 
plt.show()

 决策树最大深度max_depth: 默认可以不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间。
本数据集特征也不是很多,其实是不需要对这个参数进行调整

调整min_samples_leaf

## 调整min_samples_leaf
scorel = []
for i in range(1,20):
    RFC = RandomForestClassifier(max_depth=20,n_estimators=51,min_samples_leaf=i,
                                 n_jobs=-1,
                                 random_state=90).fit(X_train,y_train)
    score = RFC.score(X_test,y_test)
    scorel.append(score)

print(max(scorel),([*range(1,20)][scorel.index(max(scorel))]))  #112是最优的估计器数量 #最优得分是0.951462
plt.figure(figsize=[20,5])
plt.plot(range(1,20),scorel) 
plt.show()

 min_samples_split优化

# min_samples_split优化
scorel = []
for i in range(2,20):
    RFC = RandomForestClassifier(max_depth=20,n_estimators=51,min_samples_leaf=1,min_samples_split=i,
                                 n_jobs=-1,
                                 random_state=90).fit(X_train,y_train)
    score = RFC.score(X_test,y_test)
    scorel.append(score)

print(max(scorel),([*range(2,20)][scorel.index(max(scorel))]))  #112是最优的估计器数量 #最优得分是0.951462
plt.figure(figsize=[20,5])
plt.plot(range(2,20),scorel) 
plt.show()

调整max_features及其他参数

## 调整max_features
param_grid = 'max_features':['auto', 'sqrt','log2']
RFC = RandomForestClassifier(max_depth=20,n_estimators=51,min_samples_leaf=1,min_samples_split=2
                             )
GS = GridSearchCV(RFC,param_grid,cv=10)
GS.fit(X,y)
print(GS.best_params_ ) #最佳最大特征方法为log2  
print(GS.best_score_)
param_grid = 'criterion':['gini', 'entropy']
RFC = RandomForestClassifier(max_depth=20,n_estimators=51,min_samples_leaf=1,min_samples_split=2,max_features='log2')
GS = GridSearchCV(RFC,param_grid,cv=10)
GS.fit(X,y)
print(GS.best_params_ )
print(GS.best_score_)
# 调整min_samples_leaf
param_grid = 'min_samples_leaf':np.arange(1, 11, 1) 
RFC = RandomForestClassifier(max_depth=20,n_estimators=51,min_samples_leaf=1,min_samples_split=2,max_features='log2',criterion='gini')
GS = GridSearchCV(RFC,param_grid,cv=10)
GS.fit(X,y)
print(GS.best_params_ )
print(GS.best_score_)
scorel = []
for i in range(2,20):
    RFC = RandomForestClassifier(max_depth=20,n_estimators=51,min_samples_leaf=1,min_samples_split=2,max_features='log2',criterion='gini',
                                 n_jobs=-1,
                                 random_state=90).fit(X_train,y_train)
    score = RFC.score(X_test,y_test)
    scorel.append(score)

print(max(scorel),([*range(2,20)][scorel.index(max(scorel))]))  #112是最优的估计器数量 #最优得分是0.951462
plt.figure(figsize=[20,5])
plt.plot(range(2,20),scorel) 
plt.show()

网格搜索(电脑性能强)

#超参数配置
param_knn = 
'n_estimators': list(range(3,100,1)),
'max_depth':list(range(3,30,1)),
'max_features':['auto', 'sqrt','log2'],
'min_samples_leaf':list(range(1,20)),
'criterion':['gini', 'entropy'],
'min_samples_leaf':list(range(1,11))

#KNN的超参数
gsearch = GridSearchCV( model , param_grid = param_knn )
gsearch.fit( X_train, y_train )
gsearch.best_params_
gsearch.best_score_
best_=gsearch.best_estimator_
print(best_)

根据手动调参的测试,这里想要尝试一下网格搜索,但是我的机器无法完成,最后发现是内存不足,其次我去查询了一些资料,在随机森林中,一般是不需要做交叉验证的,这里的shift折交叉对电脑的显卡肯定要求严格,如果觉得自己的配置还可以的小伙伴,可以去测试一下这个代码。

随机森林做特征筛选(可视化)

feat_labels = df.columns[:-1]
# n_jobs  整数 可选(默认=1) 适合和预测并行运行的作业数,如果为-1,则将作业数设置为核心数
forest = RandomForestClassifier(max_depth=20,n_estimators=51,min_samples_leaf=1,min_samples_split=2,max_features='log2',criterion='gini',
                                random_state=0, n_jobs=-1)
forest.fit(X_train, y_train)
 
labe_name=[]
imports=[]
# 下面对训练好的随机森林,完成重要性评估
# feature_importances_  可以调取关于特征重要程度
importances = forest.feature_importances_
print("重要性:",importances)
x_columns =df.columns[:-1]
indices = np.argsort(importances)[::-1]
for f in range(X_train.shape[1]):
# 对于最后需要逆序排序,我认为是做了类似决策树回溯的取值,从叶子收敛
# 到根,根部重要程度高于叶子。
    print("%2d) %-*s %f" % (f + 1, 30, feat_labels[indices[f]], importances[indices[f]]))
    labe_name.append(feat_labels[indices[f]])
    imports.append(importances[indices[f]])
 
 
# # 筛选变量(选择重要性比较高的变量)
# threshold = 0.03
# x_selected = X_train.iloc[:,:-1][:,importances > threshold]
 
plt.figure(figsize=(10,8))
sns.barplot(imports,labe_name, orient='h')

 虽然这里筛选的特征对我们的随机森林的模型没有什么提升,但是你可以依据该模型的特征筛选去做其他模型,比如支持向量机等

结论:随机森林在这个数据集上,只需要调节n_estimators即可,就可以达到最好的效果,虽然每个参数我都尝试去利用学习曲线做优化迭代,但是效果和默认值差不多,其次利用随机森林做特征筛选,将权重大的特征带入,效果并不好,最后我还发现一个问题,随机森林因为是又放回抽样,这里的特征顺序也会影响到模型的效果,当我们把特征按照权重顺序排列。

最佳模型代码

# 最终的模型效果和代码

# 导入数据 分割数据
df=pd.read_csv(r"\\数据.csv")
X=df.iloc[:,:-1]
y=df.iloc[:,-1]
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2,stratify=y,random_state=1)

# 导入模型
model=RandomForestClassifier(n_estimators=51,max_depth=20,max_features='sqrt',criterion='gini',n_jobs=-1,random_state=90)
# 训练模型
model.fit(X_train,y_train)
# 预测值
y_pred = model.predict(X_test)

'''
评估指标
'''
# 求出预测和真实一样的数目
true = np.sum(y_pred == y_test )
print('预测对的结果数目为:', true)
print('预测错的的结果数目为:', y_test.shape[0]-true)
# 评估指标
from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score,cohen_kappa_score
print('预测数据的准确率为: :.4%'.format(accuracy_score(y_test,y_pred)*100))
print('预测数据的精确率为::.4%'.format(
      precision_score(y_test,y_pred)*100))
print('预测数据的召回率为::.4%'.format(
      recall_score(y_test,y_pred)*100))
# print("训练数据的F1值为:", f1score_train)
print('预测数据的F1值为:',
      f1_score(y_test,y_pred))
print('预测数据的Cohen’s Kappa系数为:',
      cohen_kappa_score(y_test,y_pred))
# 打印分类报告
print('预测数据的分类报告为:','\\n',
      classification_report(y_test,y_pred))

# 这行代码在jupyter notebook 上面运行不起,内存不足,需要使用本地的pycharm,好像我的也跑不起
# score_pre = cross_val_score(model,X_test,y_test,cv=5).mean() #利用所有数据,进行交叉验证以后0.976变差了
# print("十折交叉验证的平均得分".format(score_pre))

# ROC曲线、AUC
from sklearn.metrics import precision_recall_curve
from sklearn import metrics
# 预测正例的概率
y_pred_prob=model.predict_proba(X_test)[:,1]
# y_pred_prob ,返回两列,第一列代表类别0,第二列代表类别1的概率
#https://blog.csdn.net/dream6104/article/details/89218239
fpr, tpr, thresholds = metrics.roc_curve(y_test,y_pred_prob, pos_label=2)
#pos_label,代表真阳性标签,就是说是分类里面的好的标签,这个要看你的特征目标标签是0,1,还是1,2
roc_auc = metrics.auc(fpr, tpr)  #auc为Roc曲线下的面积
# print(roc_auc)
plt.figure(figsize=(8,6))
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.plot(fpr, tpr, 'r',label='AUC = %0.2f'% roc_auc)
plt.legend(loc='lower right')
# plt.plot([0, 1], [0, 1], 'r--')
plt.xlim([0, 1.1])
plt.ylim([0, 1.1])
plt.xlabel('False Positive Rate') #横坐标是fpr
plt.ylabel('True Positive Rate')  #纵坐标是tpr
plt.title('Receiver operating characteristic example')
plt.show()

 效果还是不错的,各个评估指标都比较的乐观

写到最后:

随机森林,一般还是不错的,至于参数调优,可以多测试几个版本,不管是网格搜索还是自定义迭代调参,还是先验知识,都应该跳出传统的思维,多去比较和测试,最后出来的效果才是你真正需要的,不要嫌麻烦,好的模型都是一步一步的调配出来的。

每文一语

凌晨的夜晚,格外的宁静

以上是关于机器学习分类算法之随机森林(集成学习算法)的主要内容,如果未能解决你的问题,请参考以下文章

机器学习算法 - 随机森林之决策树初探

机器学习之集成学习和随机森林

分类算法 - 随机森林

集成学习之随机森林案例专题Python机器学习系列(十七)

集成学习算法:Bagging和随机森林

随机森林算法基础梳理