机器学习之决策树与随机森林

来源:互联网 发布:linux 根目录满了 编辑:程序博客网 时间:2024/04/29 06:20

决策树是处理分类问题的最基本的算法,许多我们常用的随机森林和提升树,都是基于决策树的,先来看看决策树。
一.决策树
如果已有一颗决策树,可以简单的将一个新的样本分类,原理是从根节点出发,不断的测试对应的特征和相关的条件,直到到达一个叶节点为止。
那么我们如何构建这颗决策树呢,首先先看几个概念:
:我觉得完全可以用化学中的熵来类比理解,信息论里的是用来衡量数据不纯程度的一个指标,定义:假设有c个类,使用Pi表示样本属于第i个类的概率,则对应的熵可定义为:Entropy(S)=-∑PilogPi
基尼系数:定义:Gini(S)=1-∑Pi^2 基尼系数也是衡量数据不纯度的一个指标,说实话,我也不懂为啥要弄出这么个概念,不过我相信,可能是用这个计算或其他方面都更方便吧。
信息增益:根据熵的定义,如果一个数据集的熵较大,那么该数据集的纯度越低,在建立决策树的每一步都需要选择分类能力最强的特征,简单的说,就是分类能力较强的特征能够使得将训练划分成两个或多个子集后,每个子集的纯度更高,即熵更小。我们将划分前后熵的差称为由此特征划分所导致的信息增益。数学定义就是划分前后信息熵做差就完了。

在构建决策树的过程中,通常采用两种方式,基于基尼系数的CART,和基于信息增益的C4.5,,对于构建每一个节点,我们都用信息增益最大的特征作为划分特征。

数值和分类特征的问题对于分类特征而言,直接判断就好,对于数值变量,需要进行特殊处理,这里给个例子:我们可以搜索训练集中该变量的所有取值,并从小到大排列,将相邻取值的算数平均值作为分割点,并从中选出最优的分割点。

过拟合和剪枝我们都知道,模型复杂,容易导致过拟合,不过,我们可以通过剪枝来控制模型的复杂度,剪枝的方式有好多种,这些都是我们可以控制的,sklearn中都提供了相应的方法参数。例如,当节点的对应训练样本数量低于某一数值停止生长,或信息增益的大小小于预先设定的值,还有一种就是被称为事后剪枝,核心就是让决策树充分生长,最后自底向上剪枝,用一个节点代替一个子树。
二.随机森林
1.随机森林是集成学习的一种,那我们先来谈谈集成学习,像决策树,逻辑回归这种,在集成学习中,我们叫他基学习器,也叫弱学习器,我们通常不会要求基学习器的准确度很高,从直观上讲,虽然每个基学习器都会犯错,但是如果他们在犯不同错,则通过集成学习,那么将他们聚合起来的犯错的可能性就会降低,但是如果基学习器的模型比较相似,那么提升的幅度也不是很高
2.集成学习分为两大类:1.并行方法(bagging主要代表)2.顺序方法(boosting主要代表) 对于前者,核心思想就是通过同时构建多个基学习器,利用这些基学习器的独立性以提升最后模型的性能对于一个训练集,我们一般采用引入随机性来尽量构造相互独立的模型,对于后者,核心思想就是顺次构建学习器,当构建后面的学习器时,希望后面的学习器能够避免前面学习器的错误,从而提高聚合后的性能
3.今天我们说的随机森林就是bagging的一个典型应用。对于决策树我们知道,较深的决策树很容易导致过拟合,对于随机森林,他的随机体现在两个方面,1.构建每颗决策树时,随机选取样本数为n的可重复样本2.在构建决策树的每一步,随机取出d个变量,再取出最优的变量,对于最后结果而言:对于回归,采取所有模型的平均值输出,分类问题,以最多的类别输出
4.随机森林要指定的参数
1.决策树的数量 2.叶节点所能包含的样本数的最大值 3.每次选取最佳变量时的随机选取的变量数
这些都是我们可控的,好多机器学习大神都给出了一些可能比较好的经验值,但是具体还是要结合实际问题自己调参分析的。

三.代码实践

import numpy as npimport pandas as pdfrom sklearn import preprocessing, model_selectionfrom sklearn.tree import DecisionTreeClassifier#读取鸢尾花数据集data = pd.read_csv('C:/Users/penn/PycharmProjects/learning/iris.csv')#训练数据读取x = data.values[:,:-1]y = data.values[:,-1]#转成数值型le = preprocessing.LabelEncoder()le.fit(['Iris-setosa', 'Iris-versicolor', 'Iris-virginica'])y = le.transform(y)#取训练集,验证集,这里的参数可以自己指定x_train,x_test,y_train,y_test= model_selection.train_test_split(x,y,test_size=0.3,random_state=1)#训练模型,决策树的参数可以自己指定model = DecisionTreeClassifier(criterion='entropy', max_depth=3)model = model.fit(x_train, y_train)y_test_hat = model.predict(x_test)result = (y_test==y_test_hat)print(np.mean(result))#0.911111111111#测试不同深度对结果的影响deeps = np.arange(1,15)alist = []for deep in deeps:    model = DecisionTreeClassifier(criterion='entropy',max_depth=deep)    model.fit(x_train,y_train)    y_test_hat = model.predict(x_test)    result = (y_test==y_test_hat)    alist.append(np.mean(result))print(alist)#[0.64444444444444449, 0.91111111111111109, 0.91111111111111109, 0.9555555555555556,#  0.91111111111111109, 0.9555555555555556, 0.9555555555555556, 0.9555555555555556,#  0.9555555555555556, 0.9555555555555556, 0.9555555555555556, 0.9555555555555556,# 0.9555555555555556, 0.9555555555555556]#训练随机森林模型from sklearn.ensemble import RandomForestClassifierclf = RandomForestClassifier(n_estimators=200, criterion='entropy', max_depth=4)clf.fit(x_train,y_train)y_test_hat = clf.predict(x_test)print(np.mean(y_test_hat==y_test))#0.955555555556

sklearn中提供了相应的接口,可以让我们自己指定相应的参数,可以根据实际测试指定最优,另外可以看到,随机森林的效果要好于单纯的决策树,不过他的训练时间复杂度要高很多