决策树基础相关(一)

一、信息论基础:

熵是热力学中表征物质状态的参量之一,其物理意义是体系混乱程度的度量

信息熵

1948年,克劳德·爱尔伍德·香农将热力学中的熵引入信息论,所以也被称为香农熵 (Shannon entropy),信息熵 (information entropy)。一条信息的信息量大小和它的不确定性有直接的关系。我们需要搞清楚一件非常非常不确定的事,或者是我们一无所知的事,就需要了解大量的信息。相反,如果我们对某件事已经有了较多的了解,我们就不需要太多的信息就能把它搞清楚。所以,从这个角度,我们可以认为,信息量的度量就等于不确定性的多少

联合熵

联合熵就是度量一个联合分布的随机系统的不确定度,联合熵的物理意义是:观察一个多个随机变量的随机系统获得的信息量。下面给出两个随机变量的联合熵的定义:分布为 p(x,y)p(x,y)p(x,y) 的一对随机变量 (X,Y)(X,Y)(X,Y) ,其联合熵定义为:

H(X,Y)=−∑x∈X​∑y∈Y​p(x,y)logp(x,y)=E[logp(x,y)1​]

条件熵

条件熵 H(Y|X) 表示在已知随机变量 X 的条件下随机变量 Y 的不确定性。条件熵 H(Y|X) 定义为 X 给定条件下 Y 的条件概率分布的熵对  X 的数学期望:

条件熵 H(Y|X)相当于联合熵 H(X,Y)减去单独的熵 H(X),即:H(Y|X)=H(X,Y)−H(X)

因此,可以这样理解,描述 X 和 Y 所需的信息是描述 X 自己所需的信息,加上给定  X 的条件下具体化  Y 所需的额外信息

信息增益

信息增益在决策树算法中是用来选择特征的指标,信息增益越大,则这个特征的选择性越好,在概率中定义为:待分类的集合的熵和选定某个特征的条件熵之差(这里只的是经验熵或经验条件熵,由于真正的熵并不知道,是根据样本计算出来的),公式如下:

基尼不纯度

基尼不纯度,是指将来自集合中的某种结果随机应用在集合中,某一数据项的预期误差率。

是在进行决策树编程的时候,对于混杂程度的预测中,一种度量方式。


二、决策树的不同分类算法

ID3

 ID3由Ross Quinlan在1986年提出。ID3决策树可以有多个分支,但是不能处理特征值为连续的情况。决策树是一种贪心算法,每次选取的分割数据的特征都是当前的最佳选择,并不关心是否达到最优。在ID3中,每次根据“最大信息熵增益”选取当前最佳的特征来分割数据,并按照该特征的所有取值来切分,也就是说如果一个特征有4种取值,数据将被切分4份,一旦按某特征切分后,该特征在之后的算法执行中,将不再起作用,所以有观点认为这种切分方式过于迅速。ID3算法十分简单,核心是根据“最大信息熵增益”原则选择划分当前数据集的最好特征,信息熵是信息论里面的概念,是信息的度量方式,不确定度越大或者说越混乱,熵就越大。在建立决策树的过程中,根据特征属性划分数据,使得原本“混乱”的数据的熵(混乱度)减少,按照不同特征划分数据熵减少的程度会不一样。在ID3中选择熵减少程度最大的特征来划分数据(贪心),也就是“最大信息熵增益”原则。

C4.5

C4.5是Ross Quinlan在1993年在ID3的基础上改进而提出的。.ID3采用的信息增益度量存在一个缺点,它一般会优先选择有较多属性值的Feature,因为属性值多的Feature会有相对较大的信息增益?(信息增益反映的给定一个条件以后不确定性减少的程度,必然是分得越细的数据集确定性更高,也就是条件熵越小,信息增益越大).为了避免这个不足C4.5中是用信息增益比率(gain ratio)来作为选择分支的准则。信息增益比率通过引入一个被称作分裂信息(Split information)的项来惩罚取值较多的Feature。除此之外,C4.5还弥补了ID3中不能处理特征属性值连续的问题。但是,对连续属性值需要扫描排序,会使C4.5性能下降,

CART分类树

CART(Classification and Regression tree)分类回归树由L.Breiman,J.Friedman,R.Olshen和C.Stone于1984年提出。ID3中根据属性值分割数据,之后该特征不会再起作用,这种快速切割的方式会影响算法的准确率。CART是一棵二叉树,采用二元切分法,每次把数据切成两份,分别进入左子树、右子树。而且每个非叶子节点都有两个孩子,所以CART的叶子节点比非叶子多1。相比ID3和C4.5,CART应用要多一些,既可以用于分类也可以用于回归。CART分类时,使用基尼指数(Gini)来选择最好的数据分割的特征,gini描述的是纯度,与信息熵的含义相似。CART中每一次迭代都会降低GINI系数。下图显示信息熵增益的一半,Gini指数,分类误差率三种评价指标非常接近。回归时使用均方差作为loss function。


三、回归树原理

在回归树中,采用的是启发式的方法。假如我们有n个特征,每个特征有si(i∈(1,n))si(i∈(1,n))个取值,那我们遍历所有特征,尝试该特征所有取值,对空间进行划分,直到取到特征j的取值s,使得损失函数最小,这样就得到了一个划分点。描述该过程的公式如下:
æ失

设将输入空间划分为M个单元:R1,R2,...,RmR1,R2,...,Rm 那么每个区域的输出值就是:cm=ave(yi|xi∈Rm)cm=ave(yi|xi∈Rm)也就是该区域内所有点y值的平均数。

举个例子。如下图所示,假如我们想要对楼内居民的年龄进行回归,将楼划分为3个区域R1,R2,R3R1,R2,R3(红线),那么R1R1的输出就是第一列四个居民年龄的平均值,R2R2的输出就是第二列四个居民年龄的平均值,R3R3的输出就是第三、四列八个居民年龄的平均值。 
 

ä¸ä¸ªä¾å­


四、决策树防止过拟合手段

先剪枝:通过提前停止树的构建而对树“剪枝”,一旦停止,节点就成为树叶。该树叶可以持有子集元组中最频繁的类

限制决策树的高度和叶子结点处样本的数目

       1.定义一个高度,当决策树达到该高度时就可以停止决策树的生长,这是一种最为简单的方法;

       2.达到某个结点的实例具有相同的特征向量,即使这些实例不属于同一类,也可以停止决策树的生长。这种方法对于处理数据中的数据冲突问题非常有效;

       3.定义一个阈值,当达到某个结点的实例个数小于该阈值时就可以停止决策树的生长;

       4.定义一个阈值,通过计算每次扩张对系统性能的增益,并比较增益值与该阈值的大小来决定是否停止决策树的生长。
 

后剪枝:它首先构造完整的决策树,允许树过度拟合训练数据,然后对那些置信度不够的结点子树用叶子结点来代替,该叶子的类标号用该结点子树中最频繁的类标记。后剪枝的剪枝过程是删除一些子树,然后用其叶子节点代替,这个叶子节点所标识的类别通过大多数原则(majority class criterion)确定。所谓大多数原则,是指剪枝过程中, 将一些子树删除而用叶节点代替,这个叶节点所标识的类别用这棵子树中大多数训练样本所属的类别来标识,所标识的类称为majority class .相比于先剪枝,这种方法更常用,正是因为在先剪枝方法中精确地估计何时停止树增长很困难。

1)REP方法是一种比较简单的后剪枝的方法,在该方法中,可用的数据被分成两个样例集合:一个训练集用来形成学习到的决策树,一个分离的验证集用来评估这个决策树在后续数据上的精度,确切地说是用来评估修剪这个决策树的影响。这个方法的动机是:即使学习器可能会被训练集中的随机错误和巧合规律所误导,但验证集合不大可能表现出同样的随机波动。所以验证集可以用来对过度拟合训练集中的虚假特征提供防护检验。

   该剪枝方法考虑将书上的每个节点作为修剪的候选对象,决定是否修剪这个结点有如下步骤组成:

       1:删除以此结点为根的子树

       2:使其成为叶子结点

       3:赋予该结点关联的训练数据的最常见分类

       4:当修剪后的树对于验证集合的性能不会比原来的树差时,才真正删除该结点


五、模型评估

机器学习过程分为原型设计阶段(Prototyping)与应用阶段(Deployed), 其中有原型设计阶段(Prototyping)离线评估应用阶段(Deployed)在线评估(online evaluation).

Prototyping阶段是使用历史数据训练一个适合解决目标任务的一个或多个机器学习模型,并对模型进行验证(Validation)与离线评估(Offline evaluation),然后通过评估指标选择一个较好的模型。我们上面的例子就是Prototyping.

Deployed阶段是当模型达到设定的指标值时便将模型上线,投入生产,使用新生成的在线数据来对该模型进行在线评估(Online evaluation),在线测试不同于离线测试,有着不同的测试方法以及评价指标。最常见的便是A/B testing,它是一种统计假设检验方法。
离线评估在线评估采用不同的评估指标,在对模型进行离线评估时是采用偏经验误差的方法,在在线评估时会采用业务指标,如设备使用效率(OEE), 用户点击率等.


六、sklearn决策树参数详解

sklearn使用DecisionTreeClassifier构建决策树,这个函数,一共有12个参数:

参数说明如下:

criterion:特征选择标准,可选参数,默认是gini,可以设置为entropy。gini是基尼不纯度,是将来自集合的某种结果随机应用于某一数据项的预期误差率,是一种基于统计的思想。entropy是香农熵,也就是上篇文章讲过的内容,是一种基于信息论的思想。Sklearn把gini设为默认参数,应该也是做了相应的斟酌的,精度也许更高些?ID3算法使用的是entropy,CART算法使用的则是gini。

splitter:特征划分点选择标准,可选参数,默认是best,可以设置为random。每个结点的选择策略。best参数是根据算法选择最佳的切分特征,例如gini、entropy。random随机的在部分划分点中找局部最优的划分点。默认的”best”适合样本量不大的时候,而如果样本数据量非常大,此时决策树构建推荐”random”。

max_features:划分时考虑的最大特征数,可选参数,默认是None。寻找最佳切分时考虑的最大特征数(n_features为总共的特征数),有如下6种情况: 
如果max_features是整型的数,则考虑max_features个特征; 
如果max_features是浮点型的数,则考虑int(max_features * n_features)个特征; 
如果max_features设为auto,那么max_features = sqrt(n_features); 
如果max_features设为sqrt,那么max_featrues = sqrt(n_features),跟auto一样; 
如果max_features设为log2,那么max_features = log2(n_features); 
如果max_features设为None,那么max_features = n_features,也就是所有特征都用。 
一般来说,如果样本特征数不多,比如小于50,我们用默认的”None”就可以了,如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。

max_depth:决策树最大深,可选参数,默认是None。这个参数是这是树的层数的。层数的概念就是,比如在贷款的例子中,决策树的层数是2层。如果这个参数设置为None,那么决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。或者如果设置了min_samples_slipt参数,那么直到少于min_smaples_split个样本为止。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间。

min_samples_split:内部节点再划分所需最小样本数,可选参数,默认是2。这个值限制了子树继续划分的条件。如果min_samples_split为整数,那么在切分内部结点的时候,min_samples_split作为最小的样本数,也就是说,如果样本已经少于min_samples_split个样本,则停止继续切分。如果min_samples_split为浮点数,那么min_samples_split就是一个百分比,ceil(min_samples_split * n_samples),数是向上取整的。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。

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

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

class_weight:类别权重,可选参数,默认是None,也可以字典、字典列表、balanced。指定样本各类别的的权重,主要是为了防止训练集某些类别的样本过多,导致训练的决策树过于偏向这些类别。类别的权重可以通过{class_label:weight}这样的格式给出,这里可以自己指定各个样本的权重,或者用balanced,如果使用balanced,则算法会自己计算权重,样本量少的类别所对应的样本权重会高。当然,如果你的样本类别分布没有明显的偏倚,则可以不管这个参数,选择默认的None。

random_state:可选参数,默认是None。随机数种子。如果是证书,那么random_state会作为随机数生成器的随机数种子。随机数种子,如果没有设置随机数,随机出来的数与当前系统时间有关,每个时刻都是不同的。如果设置了随机数种子,那么相同随机数种子,不同时刻产生的随机数也是相同的。如果是RandomState instance,那么random_state是随机数生成器。如果为None,则随机数生成器使用np.random。

min_impurity_split:节点划分最小不纯度,可选参数,默认是1e-7。这是个阈值,这个值限制了决策树的增长,如果某节点的不纯度(基尼系数,信息增益,均方差,绝对差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。

presort:数据是否预排序,可选参数,默认为False,这个值是布尔值,默认是False不排序。一般来说,如果样本量少或者限制了一个深度很小的决策树,设置为true可以让划分点选择更加快,决策树建立的更加快。如果样本量太大的话,反而没有什么好处。问题是样本量少的时候,我速度本来就不慢。所以这个值一般懒得理它就可以了。

除了这些参数要注意以外,其他在调参时的注意点有:

当样本数量少但是样本特征非常多的时候,决策树很容易过拟合,一般来说,样本数比特征数多一些会比较容易建立健壮的模型

如果样本数量少但是样本特征非常多,在拟合决策树模型前,推荐先做维度规约,比如主成分分析(PCA),特征选择(Losso)或者独立成分分析(ICA)。这样特征的维度会大大减小。再来拟合决策树模型效果会好。


七、Python绘制决策树

# -*- coding: UTF-8 -*-

import numpy as np # 快速操作结构数组的工具
import pandas as pd # 数据分析处理工具
import matplotlib.pyplot as plt # 画图工具
from sklearn import datasets # 机器学习库
from sklearn.preprocessing import LabelEncoder
from sklearn import tree



# 下面的数据分为为每个用户的来源网站、位置、是否阅读FAQ、浏览网页数目、选择的服务类型(目标结果)
attr_arr=[['slashdot','USA','yes',18,'None'],
         ['google','France','yes',23,'Premium'],
         ['digg','USA','yes',24,'Basic'],
         ['kiwitobes','France','yes',23,'Basic'],
         ['google','UK','no',21,'Premium'],
         ['(direct)','New Zealand','no',12,'None'],
         ['(direct)','UK','no',21,'Basic'],
         ['google','USA','no',24,'Premium'],
         ['slashdot','France','yes',19,'None'],
         ['digg','USA','no',18,'None'],
         ['google','UK','no',18,'None'],
         ['kiwitobes','UK','no',19,'None'],
         ['digg','New Zealand','yes',12,'Basic'],
         ['slashdot','UK','no',21,'None'],
         ['google','UK','yes',18,'Basic'],
         ['kiwitobes','France','yes',19,'Basic']]

#生成属性数据集和结果数据集
dataMat = np.mat(attr_arr)
arrMat = dataMat[:,0:4]
resultMat = dataMat[:,4]

# 构造数据集成pandas结构
attr_names = ['src', 'address', 'FAQ', 'num']   #特征属性的名称
attr_pd = pd.DataFrame(data=arrMat,columns=attr_names)    #每行为一个对象,每列为一种属性,最后一个为结果值
print(attr_pd)

#将数据集中的字符串转化为代表类别的数字。因为sklearn的决策树只识别数字
le = LabelEncoder()
for col in attr_pd.columns:                                            #为每一列序列化,就是将每种字符串转化为对应的数字。用数字代表类别
    attr_pd[col] = le.fit_transform(attr_pd[col])
print(attr_pd)

# 构建决策树
clf = tree.DecisionTreeClassifier()
clf.fit(attr_pd, resultMat)
print(clf)



# 使用决策树进行预测
result = clf.predict([[1,1,1,0]])    # 输入也必须是数字的。分别代表了每个数字所代表的属性的字符串值
print(result)

# 将决策树保存成图片
from sklearn.externals.six import StringIO
import pydotplus

dot_data = StringIO()
target_name=['None','Basic','Premium']
tree.export_graphviz(clf, out_file=dot_data,feature_names=attr_names,
                     class_names=target_name,filled=True,rounded=True,
                     special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
graph.write_png('tree.png')


 

猜你喜欢

转载自blog.csdn.net/qiuye1117/article/details/88987623