简单介绍

非常多人都玩过一个游戏。通过限定次数的提问猜出对方在纸上写出的一个词,当然对方必须对我们的每一个推測做出回应,通过一连串正确或者错误的推断,假设终于我们猜出了对方的那个词。那么我们就取得了胜利。决策树的工作原理就和这个游戏相似,看以下一个例子:决策树_信息增益

上面这张图就是一个典型的决策树,我们每天出门前要想一下今天是开车还是走路呢?首先看看窗外。下雨了吗?假设有再看看究竟是雪还是雨?哇靠。是雪,开车吧。这样一个决策的过程就是在根节点处做出的,其它的节点能够相似的推导,每一个椭圆的节点都相应着我们须要考虑的属性(天气,气温,时间。地点.....)而每一个叶子节点就是我们做出的决策了,到这里就是一棵树生长的终点。

如今假设要建立一棵决策树。须要什么数据呢?须要建立的是一堆属性到最后决策的映射关系。那么训练数据集包括了一堆属性值,以及例子正确分类的值。例如以下所看到的。对于星期六,我们有一下属性,每一个属性的取值包括在了花括号内。

outlook, with values {sunny, overcast, rain}

temperature, with values {cool, mild, hot}

humidity, with values {high, normal}

windy, with values {true, false }

将各个属性去一定的值并集合在一起。就形成了一个特殊的星期天:

outlook: overcast

temperature: cool

humidity: normal

windy: false

分类的类别仅仅有两类:N(反例),P(正例),任务是建立一个分类的方式,将属性值正确的映射至分类方式。

试想假设训练例子中仅仅有两例,并且他们的属性值同样,可是相应着不同的分类,那么这样肯定不能从这种数据集中正确的分类。所以我们须要足够的原料来开锅(喂给算法学习).假设训练的例子充足,我们总是可能利用训练数据来建立一棵决策树的,所以能否不仅仅让它符合训练数据,还能在未知的数据集上表现出色?那么须要我们的决策树非常好的抓住了属性与分类值之间的联系。越是简单的树约可能在未知的数据集上表现良好,因为他的复杂度较低,可能遭遇的variance也会较低,在未知的数据中的表现更接近于在训练数据中的表现。

决策树算法

Hunt算法

从原则上讲,给定我们一个训练数据集。通过各种属性的组合能够构造指数级的决策树,找出最佳的决策树在计算上是不可行的,所以决策树是人们在复杂度和效率之间权衡的产物。如今市面上的决策树都採用了贪心算法策略。在选择划分的数据属性时,採用一系列局部最优决策来构造决策树。

他们的基础就是Hunt算法,算法的描写叙述例如以下:

Hunt算法:

在Hunt算法中,通过递归的方式建立决策树。

1:假设数据集D中全部的数据都属于一个类,那么将该节点标记为为节点。

2:假设数据集D中包括属于多个类的训练数据,那么选择一个属性将训练数据划分为较小的子集。对于測试条件的每一个输出,创建一个子女节点,并依据測试结果将D中的记录分布到子女节点中,然后对每一个子女节点反复1,2过程,对子女的子女依旧是递归的调用该算法。直至最后停止。 

ID3算法

ID3算法(Iterative Dichotomiser 3 迭代二叉树3代)是一个由Ross Quinlan发明的用于决策树的算法。这个算法便是建立在上述所介绍的奥卡姆剃刀的基础上:越是小型的决策树越优于大的决策树(be simple简单理论)。

虽然如此,该算法也不是总是生成最小的树形结构,而是一个启示式算法。

    从信息论知识中我们知道。期望信息越小。信息增益越大,从而纯度越高。

ID3算法的核心思想就是以信息增益度量属性选择,选择分裂后信息增益最大的属性进行分裂。该算法採用自顶向下的贪婪搜索遍历可能的决策树空间。

     所以,ID3的思想便是:

  1. 自顶向下的贪婪搜索遍历可能的决策树空间构造决策树(此方法是ID3算法和C4.5算法的基础);
  2. 从“哪一个属性将在树的根节点被測试”開始。
  3. 使用统计測试来确定每一个实例属性单独分类训练例子的能力,分类能力最好的属性作为树的根结点測试(怎样定义或者评判一个属性是分类能力最好的呢?这便是下文将要介绍的信息增益,or 信息增益率)。
  4. 然后为根结点属性的每一个可能值产生一个分支,并把训练例子排列到适当的分支(也就是说,例子的该属性值相应的分支)之下。
  5. 反复这个过程,用每一个分支结点关联的训练例子来选取在该点被測试的最佳属性。

这形成了对合格决策树的贪婪搜索。也就是算法从不回溯又一次考虑曾经的选择。

    下图所看到的即是用于学习布尔函数的ID3算法概要:

决策树_数据集_02

最佳的分类属性

信息增益的度量标准:熵

ID3算法的核心思想就是以信息增益度量属性选择。选择分裂后信息增益最大的属性进行分裂。

接下来,咱们就来看看这个信息增益是个什么概念。

    上述的ID3算法的核心问题是选取在树的每一个结点要測试的属性。

我们希望选择的是最有利于分类实例的属性,信息增益(Information Gain)是用来衡量给定的属性区分训练例子的能力,而ID3算法在增长树的每一步使用信息增益从候选属性中选择属性。

    为了精确地定义信息增益,我们先定义信息论中广泛使用的一个度量标准,称为(entropy),它刻画了随意例子集的纯度(purity)。给定包括关于某个目标概念的k种例子的例子集S。那么S相对这个k种分类的熵为:

决策树_d3_03

当中P表示的是每s中每一个类出现的频率,表演示例子如以下:

决策树_数据_04

假设写python代码实现熵的计算。则例如以下所看到的:

def calcShannonEnt(dataSet):
numEntries = len(dataSet)
labelCounts = {}
for featVec in dataSet:
currentLabel = featVec[-1]
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0
for key in labelCounts:
prob = float(labelCounts[key])/numEntries
shannonEnt -= prob*log(prob,2)
return shannonEnt


为了对熵有直观的了解。须要明确它究竟是干嘛的,信息论中对熵的一种解释,熵确定了要编码集合S中随意成员的分类所须要的最少二进制位数。看他的公式进一步理解,P是种类出现的概率,log(P)表示了携带的信息,试想一下假设一件事发生的概率为1,它给我们带来的信息是0。越是不确定的事情携带的信息越高,那么其与概率的加权和就代表了这个大类中不同小类所携带信息的期望,举例来说,假设S是一个关于布尔概念的有14个例子的集合。它包括9个正例和5个反例(我们採用记号[9+,5-]来概括这种数据例子),那么S相对于这个布尔例子的熵为:

Entropy([9+,5-])=-(9/14)log2(9/14)-(5/14)log2(5/14)=0.940。

依据上述这个公式,我们能够得到:S的全部成员属于同一类。Entropy(S)=0。 S的正反例子数量相等。Entropy(S)=1;S的正反例子数量不等,熵介于0,1之间。例如以下图所看到的橙色线所看到的:

决策树_信息增益_05

其它衡量最佳切割点的标准


Gini不纯度和错分率,分别在上面的图种都有表示:


决策树_数据_06




信息增益度量期望的熵减少

信息增益Gain(S,A)定义

已经有了熵作为衡量训练例子集合纯度的标准,如今能够定义属性分类训练数据的效力的度量标准。这个标准被称为“信息增益(information gain)”。

简单的说,一个属性的信息增益就是因为使用这个属性切割例子而导致的期望熵减少(或者说,样本依照某属性划分时造成熵减少的期望)。更精确地讲,一个属性A相对例子集合S的信息增益Gain(S,A)被定义为:

决策树_信息增益_07

当中 Values(A)是属性A全部可能值的集合,是S中属性A的值为v的子集。换句话来讲,Gain(S,A)是依照属性A来分类后各类熵的加权平均值,权值就是各个分类占整体样本的比例。当对S的一个随意成员的目标值编码时,Gain(S,A)的值是在知道属性A的值后能够节省的二进制位数。

以下。举个例子,假定S是一套有关天气的训练例子,描写叙述它的属性包括可能是具有Weak和Strong两个值的Wind。假定S包括14个例子,[9+,5-]。

在这14个例子中。假定正例中的6个和反例中的2个有Wind =Weak,其它的有Wind=Strong。因为依照属性Wind分类14个例子得到的信息增益能够计算例如以下。

决策树_d3_08

决策树何时停止分裂?

决策树须要有停止的条件来终止其生长的过程。一般来说最低的条件是:当该节点以下的全部记录都属于同一类。或者当全部的记录属性都具有同样的值时。这两种条件是停止决策树的必要条件,也是最低的条件,在实际运用中我们希望决策树提前停止生长,限定叶节点包括的最低数据量,防止因为过度生长造成的过拟合是十分重要的。

决策树的优劣势和解决的方法

决策树的优势

·简单易用,并且输出的结果易于解释,树能够被图形化。加深了直观的理解。

·差点儿不须要对数据进行预处理。

·算法的开销不大,并且决策树一旦建立,对于未知样本的分类十分快,最坏情况下的时间复杂度是O(w),w是树的最大深度。

·能够用于多类的分类。

·能够容忍噪点。

决策树的劣势

·easy过拟合。

·easy被类别中占多数的类影响而产生bias,所以推荐在送入算法之间先平衡下数据中各个类别所占的比例。

·决策树採用的是自顶向下的递归划分法。因此自定而下到了末端枝叶包括的数据量会非常少。我们会依据非常少的数据量取做决策,这种决策是不具有统计意义的。这就是数据碎片的问题。

解决方法

处理决策树中的过拟合问题:

过拟合主要是决策树生长的节点过多导致的,所以对于过拟合问题,治本的方法还在于剪枝。剪枝能够分为先剪枝和后剪枝。以下对不同的情况做出讨论:

1:先剪枝:

这个方案中,我们在算法还未进行时,给它一个限制。让其最大深度在增长过程达到一定程度时停止增长。为了达到这一点我们须要採取更加苛刻的停止条件,如:当观察到最大信息增益低于某个值时停止增长,或者限制决策树的最大深度和最低叶节点分裂样本数,可是这个方案操作起来较为困难。怎样选取最佳的參数?阈值设置太高easy导致模型的过拟合。设置太低又easy导致欠拟合。那么就须要我们将这些參数也添加整个树的反复建立測试中,依据測试的结果採用表现最好的树。

2:后剪枝:

该方法中,决策树依照最大规模疯狂的生长。我们将得到一颗最大深度的决策树,然后进行剪枝的步骤,修建的顺序是从下往上。修建的方式有:1.用叶节点来替换子树,叶节点的类别有子树以下的多类决定。(子树替换)2.用子树种最经常使用的分支来替代子树(子树替换) 

构造决策树

Sklearn.tree

在强大的机器学习库sklearn中已经集成了决策树模型。所以我们能够利用该模块方便的实施决策树学习。

以下介绍一些经常使用的方法:

class sklearn.tree.DecisionTreeClassifier(criterion='gini'splitter='best'max_depth=Nonemin_samples_split=2,min_samples_leaf=1max_features=Nonerandom_state=Nonemin_density=Nonecompute_importances=None,max_leaf_nodes=None)

在创建一个决策树分类器时,我们有非常多參数能够初始化。当中主要须要考虑的是:

criterion :规定了该决策树所採用的的最佳切割属性的判决方法,有两种:“gini”。“entropy”。

max_depth :限定了决策树的最大深度,对于防止过拟合非常实用。

min_samples_leaf :限定了叶子节点包括的最小样本数,这个属性对于防止上文讲到的数据碎片问题非常有作用。

模块中一些重要的属性方法:

n_classes_ :决策树中的类数量。

classes_ :返回决策树中的全部种类标签。

feature_importances_ :feature的重要性。值越大那么越重要。

fit(Xysample_mask=NoneX_argsorted=Nonecheck_input=Truesample_weight=None)

将数据集x,和标签集y送入分类器进行训练,这里要注意一个參数是:sample_weright,它和样本的数量一样长,所携带的是每一个样本的权重。

get_params(deep=True)

得到决策树的各个參数。

set_params(**params)

调整决策树的各个參数。

predict(X)

送入样本X,得到决策树的预測。能够同一时候送入多个样本。

transform(Xthreshold=None)

返回X的较重要的一些feature。相当于裁剪数据。

score(Xysample_weight=None)

返回在数据集X,y上的測试分数,正确率。

以下是一个应用的例子:

from sklearn import tree
X = [[0, 0], [1, 1]]
Y = [0, 1]
clf = tree.DecisionTreeClassifier()
clf = clf.fit(X, Y)
clf.predict([[2., 2.]])


输出决策树结果

利用python中的pydot模块能够方便的输出决策树的效果图。只是须要注意的是pyparsing必须是旧版本号的,比方1.5,另外须要在电脑商安装Graphviz软件。

以下是一个例子:

from sklearn.externals.six import StringIO  
import pydot
dot_data = StringIO.StringIO()
tree.export_graphviz(clf, out_file=dot_data)
graph = pydot.graph_from_dot_data(dot_data.getvalue())
graph.write_pdf("iris.pdf")


使用建议

·当我们数据中的feature较多时,一定要有足够的数据量来支撑我们的算法,不然的话非常easyoverfitting

·PCA是一种避免高维数据overfitting的办法。

·从一棵较小的树開始探索,用export方法打印出来看看。

·善用max_depth參数,缓慢的添加并測试模型,找出最好的那个depth。

·善用min_samples_split和min_samples_leaf參数来控制叶子节点的样本数量,防止overfitting。

·平衡训练数据中的各个种类的数据,防止一个种类的数据dominate。





參考文献

Pang-Ning Tan  《数据挖掘导论》

Tom M Mitchell  《机器学习》

Peter Harrington  《机器学习实战》

Trevor Hastie/Robert Tibshirani/Jerome Friedman   《The Elements of Statistical Learning》

Sklearn:decision tree    http://scikit-learn.org/stable/modules/tree.html

JR Quinlan  《Introduction decision tree》1986

JR Quinlan  《C4.5 programs for machine learning》1993