随机森林算法的理论知识
随机森林是一种有监督学习算法,是以决策树为基学习器的集成学习算法。随机森林非常简单,易于实现,计算开销也很小,但是它在分类和回归上表现出非常惊人的性能,因此,随机森林被誉为“代表集成学习技术水平的方法”。
一,随机森林的随机性体现在哪几个方面?
1,数据集的随机选取
从原始的数据集中采取有放回的抽样(bagging),构造子数据集,子数据集的数据量是和原始数据集相同的。不同子数据集的元素可以重复,同一个子数据集中的元素也可以重复。
2,待选特征的随机选取
与数据集的随机选取类似,随机森林中的子树的每一个分裂过程并未用到所有的待选特征,而是从所有的待选特征中随机选取一定的特征,之后再在随机选取的特征中选取最优的特征
二,为什么使用随机森林?
1,随机森林既可以用于分类问题,也可以用于回归问题
2,过拟合是个关键的问题,可能会让模型的结果变得糟糕,但是对于随机森林来说,如果随机森林的树足够多,那么分类器就不会过拟合模型
3,随机森林分类器可以处理缺失值
4,随机森林分类器可以用分类值建模
三,随机森林的构建过程
1,从原始训练集中使用Bootstraping方法随机有放回采样取出m个样本,共进行n_tree次采样。生成n_tree个训练集
2,对n_tree个训练集,我们分别训练n_tree个决策树模型
3,对于单个决策树模型,假设训练样本特征的个数为n,那么每次分裂时根据信息增益/信息增益比/基尼指数 选择最好的特征进行分裂
4,每棵树都已知这样分裂下去,知道该节点的所有训练样例都属于同一类。在决策树的分裂过程中不需要剪枝
5,将生成的多颗决策树组成随机森林。对于分类问题,按照多棵树分类器投票决定最终分类结果;对于回归问题,由多颗树预测值的均值决定最终预测结果
注意:OOB(out-of-bag ):每棵决策树的生成都需要自助采样,这时就有1/3的数据未被选中,这部分数据就称为袋外数据。
四,随机森林优缺点总结
优点
- 由于采用了集成算法,本身精度比大多数单个算法要好,所以准确性高
- 在测试集上表现良好,由于两个随机性的引入,使得随机森林不容易陷入过拟合(样本随机,特征随机)
- 在工业上,由于两个随机性的引入,使得随机森林具有一定的抗噪声能力,对比其他算法具有一定优势
- 由于树的组合,使得随机森林可以处理非线性数据,本身属于非线性分类(拟合)模型
- 它能够处理很高维度(feature很多)的数据,并且不用做特征选择,对数据集的适应能力强:既能处理离散型数据,也能处理连续型数据,数据集无需规范化
- 训练速度快,可以运用在大规模数据集上
- 可以处理缺省值(单独作为一类),不用额外处理
- 由于有袋外数据(OOB),可以在模型生成过程中取得真实误差的无偏估计,且不损失训练数据量
- 在训练过程中,能够检测到feature间的互相影响,且可以得出feature的重要性,具有一定参考意义
- 由于每棵树可以独立、同时生成,容易做成并行化方法
- 由于实现简单、精度高、抗过拟合能力强,当面对非线性数据时,适于作为基准模型
缺点
- 当随机森林中的决策树个数很多时,训练时需要的空间和时间会比较大
- 随机森林中还有许多不好解释的地方,有点算是黑盒模型
- 在某些噪音比较大的样本集上,RF的模型容易陷入过拟合
五,特征重要性评估
现实情况下,一个数据集中往往有成百上千个特征,如何在其中选择比结果影响最大的那几个特征,以此来缩减建立模型时特征数是我们比较关心的问题。这样的方法其实很多,比如主成分分析,lasso等等。不过这里我们学习的是用随机森林来进行特征筛选。
用随机森林进行特征重要性评估的思想就是看每个特征在随机森林中的每棵树上做了多大的贡献,然后取个平均值,最后比一比特征之间的贡献大小。
贡献大小通常使用基尼指数(Gini index)或者袋外数据(OOB)错误率作为评估指标来衡量。这里我们再学习一下基尼指数来评价的方法。
我们将变量重要性评分(variable importance measures)用VIM来表示,将Gini指数用GI来表示,假设m个特征X1,X2,X3,......Xc,现在要计算出每个特征Xj的Gini指数评分VIMj(Gini),亦即第j个特征在RF所有决策树中节点分裂不纯度的平均改变量。
Gini指数的计算公式为:
其中,K表示有K个类别。Pmk表示节点m中类列k所占的比例。
直观的说,就是随便从节点m中随机抽取两个样本,其类别标记不一致的概率。
特征Xj在节点m的重要性,即节点m分支前后的Gini指数变化量为:
其中,GIl和GIr分别表示分枝后两个新节点的Gini指数。
如果,特征Xj在决策树i中出现的节点在集合M中,那么Xj在第i颗树的重要性为:
假设RF中共有n颗树,那么
最后,把所有求得的重要性评分做一个归一化处理即可。
5.1 特征选择
5.1.1 特征选择的步骤
在特征重要性的基础上,特征选择的步骤如下:
- 计算每个特征的重要性,并按降序排序
- 确定要剔除的比例,依据特征重要性剔除相应比例的特征,得到一个新的特征集
- 用新的特征集重复上述过程,直到剩下m个特征(m为提前设定的值)
- 根据上述代码中得到的各个特征集合特征集对应的袋外误差率,选择袋外误差率最低的特征集
5.1.2 特征重要性的估计方法
特征重要性的估计通常有两种方法:一是使用uniform或者gaussian抽取随机值替换原特征;一是通过permutation的方式将原来的所有N个样本的第i个特征值重新打乱分布,第二种方法更加科学,保证了特征替代值与原特征的分布是近似的。这种方法叫做permutation test ,即在计算第i个特征的重要性的时候,将N 个特征的第i个特征重新洗牌,然后比较D和表现的差异性,如果差异很大,则表明第i个特征是重要的。
5.2 示例——利用随机森林进行特征选择,然后使用SVR进行训练
1,利用随机森林进行特征选择
代码:
- import numpy as np
- import pandas as pd
- from sklearn.ensemble import RandomForestClassifier
-
- # url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data'
- url1 = pd.read_csv(r'wine.txt',header=None)
- # url1 = pd.DataFrame(url1)
- # df = pd.read_csv(url1,header=None)
- url1.columns = ['Class label', 'Alcohol', 'Malic acid', 'Ash',
- 'Alcalinity of ash', 'Magnesium', 'Total phenols',
- 'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins',
- 'Color intensity', 'Hue', 'OD280/OD315 of diluted wines', 'Proline']
- # print(url1)
-
- # 查看几个标签
- # Class_label = np.unique(url1['Class label'])
- # print(Class_label)
- # 查看数据信息
- # info_url = url1.info()
- # print(info_url)
-
- # 除去标签之外,共有13个特征,数据集的大小为178,
- # 下面将数据集分为训练集和测试集
- from sklearn.model_selection import train_test_split
- print(type(url1))
- # url1 = url1.values
- # x = url1[:,0]
- # y = url1[:,1:]
- x,y = url1.iloc[:,1:].values,url1.iloc[:,0].values
- x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.3,random_state=0)
- feat_labels = url1.columns[1:]
- # n_estimators:森林中树的数量
- # n_jobs 整数 可选(默认=1) 适合和预测并行运行的作业数,如果为-1,则将作业数设置为核心数
- forest = RandomForestClassifier(n_estimators=10000, random_state=0, n_jobs=-1)
- forest.fit(x_train, y_train)
-
- # 下面对训练好的随机森林,完成重要性评估
- # feature_importances_ 可以调取关于特征重要程度
- importances = forest.feature_importances_
- print("重要性:",importances)
- x_columns = url1.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]]))
- # 筛选变量(选择重要性比较高的变量)
- threshold = 0.15
- x_selected = x_train[:,importances > threshold]
-
- # 可视化
- import matplotlib.pyplot as plt
- plt.figure(figsize=(10,6))
- plt.title("红酒的数据集中各个特征的重要程度",fontsize = 18)
- plt.ylabel("import level",fontsize = 15,rotation=90)
- plt.rcParams['font.sans-serif'] = ["SimHei"]
- plt.rcParams['axes.unicode_minus'] = False
- for i in range(x_columns.shape[0]):
- plt.bar(i,importances[indices[i]],color='orange',align='center')
- plt.xticks(np.arange(x_columns.shape[0]),x_columns,rotation=90,fontsize=15)
- plt.show()
结果:
- RangeIndex: 178 entries, 0 to 177
- Data columns (total 14 columns):
- Class label 178 non-null int64
- Alcohol 178 non-null float64
- Malic acid 178 non-null float64
- Ash 178 non-null float64
- Alcalinity of ash 178 non-null float64
- Magnesium 178 non-null int64
- Total phenols 178 non-null float64
- Flavanoids 178 non-null float64
- Nonflavanoid phenols 178 non-null float64
- Proanthocyanins 178 non-null float64
- Color intensity 178 non-null float64
- Hue 178 non-null float64
- OD280/OD315 of diluted wines 178 non-null float64
- Proline 178 non-null int64
- dtypes: float64(11), int64(3)
- memory usage: 19.5 KB
- 重要性: [0.10658906 0.02539968 0.01391619 0.03203319 0.02207807 0.0607176
- 0.15094795 0.01464516 0.02235112 0.18248262 0.07824279 0.1319868
- 0.15860977]
- 1) Color intensity 0.182483
- 2) Proline 0.158610
- 3) Flavanoids 0.150948