thinkphp企业网站系统,网页网站设计培训班,网站工作室模板,wordpress文章外部链接决策树 决策树(decision tree)是一种基本的分类与回归方法。 举个通俗易懂的例子#xff0c;如下图所示的流程图就是一个决策树#xff0c;长方形代表判断模块(decision block)#xff0c;椭圆形成代表终止模块(terminating block)#xff0c;表示已经得出结论#xff0c;…决策树 决策树(decision tree)是一种基本的分类与回归方法。 举个通俗易懂的例子如下图所示的流程图就是一个决策树长方形代表判断模块(decision block)椭圆形成代表终止模块(terminating block)表示已经得出结论可以终止运行。从判断模块引出的左右箭头称作为分支(branch)它可以达到另一个判断模块或者终止模块。我们还可以这样理解分类决策树模型是一种描述对实例进行分类的树形结构。决策树由结点(node)和有向边(directed edge)组成。结点有两种类型内部结点(internal node)和叶结点(leaf node)。内部结点表示一个特征或属性叶结点表示一个类。如下图所示的决策树长方形和椭圆形都是结点。长方形的结点属于内部结点椭圆形的结点属于叶结点从结点引出的左右箭头就是有向边。而最上面的结点就是决策树的根结点(root node)。 这就是一个假想的相亲对象分类系统。它首先检测相亲对方是否有房。如果有房则对于这个相亲对象可以考虑进一步接触。如果没有房则观察相亲对象是否有上进心如果没有直接Say Goodbye此时可以说你人很好但是我们不合适。如果有则可以把这个相亲对象列入候选名单好听点叫候选名单有点瑕疵地讲那就是备胎。 把决策树看成一个if-then规则的集合将决策树转换成if-then规则的过程是这样的由决策树的根结点(root node)到叶结点(leaf node)的每一条路径构建一条规则路径上内部结点的特征对应着规则的条件而叶结点的类对应着规则的结论。决策树的路径或其对应的if-then规则集合具有一个重要的性质互斥并且完备。这就是说每一个实例都被一条路径或一条规则所覆盖而且只被一条路径或一条规则所覆盖。这里所覆盖是指实例的特征与路径上的特征一致或实例满足规则的条件。
使用决策树做预测需要以下过程
收集数据可以使用任何方法。比如想构建一个相亲系统我们可以从媒婆那里或者通过采访相亲对象获取数据。根据他们考虑的因素和最终的选择结果就可以得到一些供我们利用的数据了。准备数据收集完的数据我们要进行整理将这些所有收集的信息按照一定规则整理出来并排版方便我们进行后续处理。分析数据可以使用任何方法决策树构造完成之后我们可以检查决策树图形是否符合预期。训练算法这个过程也就是构造决策树同样也可以说是决策树学习就是构造一个决策树的数据结构。测试算法使用经验树计算错误率。当错误率达到了可接收范围这个决策树就可以投放使用了。使用算法此步骤可以使用适用于任何监督学习算法而使用决策树可以更好地理解数据的内在含义。
决策树的构建的准备工作 使用决策树做预测的每一步骤都很重要数据收集不到位将会导致没有足够的特征让我们构建错误率低的决策树。数据特征充足但是不知道用哪些特征好将会导致无法构建出分类效果好的决策树模型。从算法方面看决策树的构建是我们的核心内容。
这一过程可以概括为3个步骤特征选择、决策树的生成和决策树的修剪
1.特征选择 特征选择在于选取对于数据具有分类能力的特征。这样可以提高决策树学习的效率如果利用一个特征进行分类的结果与随机分类的结果没有很大差别则称这个特征是没有分类能力的。经验上扔掉这样的特征对决策树学习的精度影响不大。通常特征选择的标准是信息增益(information gain)或信息增益比为了简单本文使用信息增益作为选择特征的标准。 再讨论信息增益之前先看一组实例。 希望通过所给的训练数据学习一个贷款申请的决策树用于是否通过贷款申请进行分类即当新的客户提出贷款申请时根据申请人的特征利用决策树决定是否批准贷款申请。 特征选择就是决定用哪个特征来划分特征空间。比如我们通过上述数据表得到两个可能的决策树分别由两个不同特征的根结点构成。 图(a)所示的根结点的特征是年龄有3个取值对应于不同的取值有不同的子结点。图(b)所示的根节点的特征是工作有2个取值对应于不同的取值有不同的子结点。两个决策树都可以从此延续下去。问题是究竟选择哪个特征更好些这就要求确定选择特征的准则。直观上如果一个特征具有更好的分类能力或者说按照这一特征将训练数据集分割成子集使得各个子集在当前条件下有最好的分类那么就更应该选择这个特征。信息增益就能够很好地表示这一直观的准则。 在划分数据集之后信息发生的变化称为信息增益知道如何计算信息增益我们就可以计算每个特征值划分数据集获得的信息增益获得信息增益最高的特征就是最好的选择。
香农熵 熵定义为信息的期望值。在信息论与概率统计中熵是表示随机变量不确定性的度量。如果待分类的事物可能划分在多个分类之中则符号xi的信息定义为 为了计算熵我们需要计算所有类别所有可能值包含的信息期望值(数学期望)通过下面的公式得到 其中n是分类的数目。熵越大随机变量的不确定性就越大。
当熵中的概率由数据估计(特别是最大似然估计)得到时所对应的熵称为经验熵(empirical entropy)。什么叫数据估计比如有10个数据一共有两个类别A类和B类。其中有7个数据属于A类则该A类的概率即为十分之七。其中有3个数据属于B类则该B类的概率即为十分之三。浅显的解释就是这概率是我们根据数据数出来的。我们定义贷款申请样本数据表中的数据为训练数据集D则训练数据集D的经验熵为H(D)|D|表示其样本容量及样本个数。设有K个类Ck1,2,3,...,K,|Ck|为属于类Ck的样本个数因此经验熵公式就可以写为 用代码计算经验熵 在编写代码之前我们先对数据集进行属性标注。
年龄0代表青年1代表中年2代表老年有工作0代表否1代表是有自己的房子0代表否1代表是信贷情况0代表一般1代表好2代表非常好类别(是否给贷款)no代表否yes代表是。
# -*- coding: UTF-8 -*-
from math import log
def createDataSet():dataSet [[0, 0, 0, 0, no], #数据集[0, 0, 0, 1, no],[0, 1, 0, 1, yes],[0, 1, 1, 0, yes],[0, 0, 0, 0, no],[1, 0, 0, 0, no],[1, 0, 0, 1, no],[1, 1, 1, 1, yes],[1, 0, 1, 2, yes],[1, 0, 1, 2, yes],[2, 0, 1, 2, yes],[2, 0, 1, 1, yes],[2, 1, 0, 1, yes],[2, 1, 0, 2, yes],[2, 0, 0, 0, no]]labels [不放贷, 放贷] #分类属性return dataSet, labels #返回数据集和分类属性
def calcShannonEnt(dataSet):numEntires len(dataSet) #返回数据集的行数labelCounts {} #保存每个标签(Label)出现次数的字典for featVec in dataSet: #对每组特征向量进行统计currentLabel featVec[-1] #提取标签(Label)信息if currentLabel not in labelCounts.keys(): #如果标签(Label)没有放入统计次数的字典,添加进去labelCounts[currentLabel] 0labelCounts[currentLabel] 1 #Label计数shannonEnt 0.0 #经验熵(香农熵)for key in labelCounts: #计算香农熵prob float(labelCounts[key]) / numEntires #选择该标签(Label)的概率shannonEnt - prob * log(prob, 2) #利用公式计算return shannonEnt #返回经验熵(香农熵)if __name__ __main__:dataSet, features createDataSet()#print(dataSet)print(calcShannonEnt(dataSet)) 计算结果与手算的一致
信息增益 信息增益是相对于特征而言的信息增益越大特征对最终的分类结果影响也就越大我们就应该选择对最终分类结果影响最大的那个特征作为我们的分类特征。 条件熵H(Y|X)表示在已知随机变量X的条件下随机变量Y的不确定性随机变量X给定的条件下随机变量Y的条件熵(conditional entropy)H(Y|X)定义为X给定条件下Y的条件概率分布的熵对X的数学期望 同理当条件熵中的概率由数据估计(特别是极大似然估计)得到时所对应的条件熵称为条件经验熵。明确了条件熵和经验条件熵的概念。接下来让我们说说信息增益。前面也提到了信息增益是相对于特征而言的。所以特征A对训练数据集D的信息增益g(D,A)定义为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差即 一般地熵H(D)与条件熵H(D|A)之差称为互信息(mutual information)。决策树学习中的信息增益等价于训练数据集中类与特征的互信息。设特征A有n个不同的取值{a1,a2,···,an}根据特征A的取值将D划分为n个子集{D1,D2···,Dn}|Di|为Di的样本个数。记子集Di中属于Ck的样本的集合为Dik即Dik Di ∩ Ck|Dik|为Dik的样本个数。于是经验条件熵的公式可以些为 以贷款申请样本数据表为例进行说明。看下年龄这一列的数据也就是特征A1一共有三个类别分别是青年、中年和老年。我们只看年龄是青年的数据年龄是青年的数据一共有5个所以年龄是青年的数据在训练数据集出现的概率是十五分之五也就是三分之一。同理年龄是中年和老年的数据在训练数据集出现的概率也都是三分之一。现在我们只看年龄是青年的数据的最终得到贷款的概率为五分之二因为在五个数据中只有两个数据显示拿到了最终的贷款同理年龄是中年和老年的数据最终得到贷款的概率分别为五分之三、五分之四。所以计算年龄的信息增益过程如下 同理计算其余特征的信息增益g(D,A2)、g(D,A3)和g(D,A4)。分别为 最后比较特征的信息增益由于特征A3(有自己的房子)的信息增益值最大所以选择A3作为最优特征。
# -*- coding: UTF-8 -*-
from math import logdef calcShannonEnt(dataSet):numEntires len(dataSet) #返回数据集的行数labelCounts {} #保存每个标签(Label)出现次数的字典for featVec in dataSet: #对每组特征向量进行统计currentLabel featVec[-1] #提取标签(Label)信息if currentLabel not in labelCounts.keys(): #如果标签(Label)没有放入统计次数的字典,添加进去labelCounts[currentLabel] 0labelCounts[currentLabel] 1 #Label计数shannonEnt 0.0 #经验熵(香农熵)for key in labelCounts: #计算香农熵prob float(labelCounts[key]) / numEntires #选择该标签(Label)的概率shannonEnt - prob * log(prob, 2) #利用公式计算return shannonEnt #返回经验熵(香农熵)def createDataSet():dataSet [[0, 0, 0, 0, no], #数据集[0, 0, 0, 1, no],[0, 1, 0, 1, yes],[0, 1, 1, 0, yes],[0, 0, 0, 0, no],[1, 0, 0, 0, no],[1, 0, 0, 1, no],[1, 1, 1, 1, yes],[1, 0, 1, 2, yes],[1, 0, 1, 2, yes],[2, 0, 1, 2, yes],[2, 0, 1, 1, yes],[2, 1, 0, 1, yes],[2, 1, 0, 2, yes],[2, 0, 0, 0, no]]labels [不放贷, 放贷] #分类属性return dataSet, labels #返回数据集和分类属性def splitDataSet(dataSet, axis, value): retDataSet [] #创建返回的数据集列表for featVec in dataSet: #遍历数据集if featVec[axis] value:reducedFeatVec featVec[:axis] #去掉axis特征reducedFeatVec.extend(featVec[axis1:]) #将符合条件的添加到返回的数据集retDataSet.append(reducedFeatVec)return retDataSet #返回划分后的数据集def chooseBestFeatureToSplit(dataSet):numFeatures len(dataSet[0]) - 1 #特征数量baseEntropy calcShannonEnt(dataSet) #计算数据集的香农熵bestInfoGain 0.0 #信息增益bestFeature -1 #最优特征的索引值for i in range(numFeatures): #遍历所有特征#获取dataSet的第i个所有特征featList [example[i] for example in dataSet]uniqueVals set(featList) #创建set集合{},元素不可重复newEntropy 0.0 #经验条件熵for value in uniqueVals: #计算信息增益subDataSet splitDataSet(dataSet, i, value) #subDataSet划分后的子集prob len(subDataSet) / float(len(dataSet)) #计算子集的概率newEntropy prob * calcShannonEnt(subDataSet) #根据公式计算经验条件熵infoGain baseEntropy - newEntropy #信息增益print(第%d个特征的增益为%.3f % (i, infoGain)) #打印每个特征的信息增益if (infoGain bestInfoGain): #计算信息增益bestInfoGain infoGain #更新信息增益找到最大的信息增益bestFeature i #记录信息增益最大的特征的索引值return bestFeature #返回信息增益最大的特征的索引值if __name__ __main__:dataSet, features createDataSet()print(最优特征索引值: str(chooseBestFeatureToSplit(dataSet))) 最优特征的索引值为2也就是特征A3(有自己的房子)。
2.决策树的生成和修剪 已经学习了从数据集构造决策树算法所需要的子功能模块包括经验熵的计算和最优特征的选择其工作原理如下得到原始数据集然后基于最好的属性值划分数据集由于特征值可能多于两个因此可能存在大于两个分支的数据集划分。第一次划分之后数据集被向下传递到树的分支的下一个结点。在这个结点上我们可以再次划分数据。因此我们可以采用递归的原则处理数据集。 构建决策树的算法有很多比如C4.5、ID3和CART这些算法在运行时并不总是在每次划分数据分组时都会消耗特征。由于特征数目并不是每次划分数据分组时都减少因此这些算法在实际使用时可能引起一定的问题。目前我们并不需要考虑这个问题只需要在算法开始运行前计算列的数目查看算法是否使用了所有属性即可。 决策树生成算法递归地产生决策树直到不能继续下去未为止。这样产生的树往往对训练数据的分类很准确但对未知的测试数据的分类却没有那么准确即出现过拟合现象。过拟合的原因在于学习时过多地考虑如何提高对训练数据的正确分类从而构建出过于复杂的决策树。解决这个问题的办法是考虑决策树的复杂度对已生成的决策树进行简化。 ID3算法的核心是在决策树各个结点上对应信息增益准则选择特征递归地构建决策树。具体方法是从根结点(root node)开始对结点计算所有可能的特征的信息增益选择信息增益最大的特征作为结点的特征由该特征的不同取值建立子节点再对子结点递归地调用以上方法构建决策树直到所有特征的信息增益均很小或没有特征可以选择为止。最后得到一个决策树。ID3相当于用极大似然法进行概率模型的选择。
再次回顾上述放贷的数据 由于特征A3(有自己的房子)的信息增益值最大所以选择特征A3作为根结点的特征。它将训练集D划分为两个子集D1(A3取值为是)和D2(A3取值为否)。由于D1只有同一类的样本点所以它成为一个叶结点结点的类标记为“是”。
对D2则需要从特征A1(年龄)A2(有工作)和A4(信贷情况)中选择新的特征计算各个特征的信息增益 根据计算选择信息增益最大的特征A2(有工作)作为结点的特征。由于A2有两个可能取值从这一结点引出两个子结点一个对应是(有工作)的子结点包含3个样本它们属于同一类所以这是一个叶结点类标记为是另一个是对应否(无工作)的子结点包含6个样本它们也属于同一类所以这也是一个叶结点类标记为否。
该决策树只用了两个特征(有两个内部结点)生成的决策树如下图所示。 编写代码构建决策树
使用字典存储决策树
{有自己的房子: {0: {有工作: {0: no, 1: yes}}, 1: yes}}
# -*- coding: UTF-8 -*-
from math import log
import operatordef calcShannonEnt(dataSet):numEntires len(dataSet) #返回数据集的行数labelCounts {} #保存每个标签(Label)出现次数的字典for featVec in dataSet: #对每组特征向量进行统计currentLabel featVec[-1] #提取标签(Label)信息if currentLabel not in labelCounts.keys(): #如果标签(Label)没有放入统计次数的字典,添加进去labelCounts[currentLabel] 0labelCounts[currentLabel] 1 #Label计数shannonEnt 0.0 #经验熵(香农熵)for key in labelCounts: #计算香农熵prob float(labelCounts[key]) / numEntires #选择该标签(Label)的概率shannonEnt - prob * log(prob, 2) #利用公式计算return shannonEnt #返回经验熵(香农熵)def createDataSet():dataSet [[0, 0, 0, 0, no], #数据集[0, 0, 0, 1, no],[0, 1, 0, 1, yes],[0, 1, 1, 0, yes],[0, 0, 0, 0, no],[1, 0, 0, 0, no],[1, 0, 0, 1, no],[1, 1, 1, 1, yes],[1, 0, 1, 2, yes],[1, 0, 1, 2, yes],[2, 0, 1, 2, yes],[2, 0, 1, 1, yes],[2, 1, 0, 1, yes],[2, 1, 0, 2, yes],[2, 0, 0, 0, no]]labels [年龄, 有工作, 有自己的房子, 信贷情况] #特征标签return dataSet, labels #返回数据集和分类属性def splitDataSet(dataSet, axis, value): retDataSet [] #创建返回的数据集列表for featVec in dataSet: #遍历数据集if featVec[axis] value:reducedFeatVec featVec[:axis] #去掉axis特征reducedFeatVec.extend(featVec[axis1:]) #将符合条件的添加到返回的数据集retDataSet.append(reducedFeatVec)return retDataSet #返回划分后的数据集def chooseBestFeatureToSplit(dataSet):numFeatures len(dataSet[0]) - 1 #特征数量baseEntropy calcShannonEnt(dataSet) #计算数据集的香农熵bestInfoGain 0.0 #信息增益bestFeature -1 #最优特征的索引值for i in range(numFeatures): #遍历所有特征#获取dataSet的第i个所有特征featList [example[i] for example in dataSet]uniqueVals set(featList) #创建set集合{},元素不可重复newEntropy 0.0 #经验条件熵for value in uniqueVals: #计算信息增益subDataSet splitDataSet(dataSet, i, value) #subDataSet划分后的子集prob len(subDataSet) / float(len(dataSet)) #计算子集的概率newEntropy prob * calcShannonEnt(subDataSet) #根据公式计算经验条件熵infoGain baseEntropy - newEntropy #信息增益# print(第%d个特征的增益为%.3f % (i, infoGain)) #打印每个特征的信息增益if (infoGain bestInfoGain): #计算信息增益bestInfoGain infoGain #更新信息增益找到最大的信息增益bestFeature i #记录信息增益最大的特征的索引值return bestFeature #返回信息增益最大的特征的索引值def majorityCnt(classList):classCount {}for vote in classList: #统计classList中每个元素出现的次数if vote not in classCount.keys():classCount[vote] 0 classCount[vote] 1sortedClassCount sorted(classCount.items(), key operator.itemgetter(1), reverse True) #根据字典的值降序排序return sortedClassCount[0][0] #返回classList中出现次数最多的元素def createTree(dataSet, labels, featLabels):classList [example[-1] for example in dataSet] #取分类标签(是否放贷:yes or no)if classList.count(classList[0]) len(classList): #如果类别完全相同则停止继续划分return classList[0]if len(dataSet[0]) 1 or len(labels) 0: #遍历完所有特征时返回出现次数最多的类标签return majorityCnt(classList)bestFeat chooseBestFeatureToSplit(dataSet) #选择最优特征bestFeatLabel labels[bestFeat] #最优特征的标签featLabels.append(bestFeatLabel)myTree {bestFeatLabel:{}} #根据最优特征的标签生成树del(labels[bestFeat]) #删除已经使用特征标签featValues [example[bestFeat] for example in dataSet] #得到训练集中所有最优特征的属性值uniqueVals set(featValues) #去掉重复的属性值for value in uniqueVals: #遍历特征创建决策树。 subLabels labels[:] myTree[bestFeatLabel][value] createTree(splitDataSet(dataSet, bestFeat, value), subLabels, featLabels)return myTreeif __name__ __main__:dataSet, labels createDataSet()featLabels []myTree createTree(dataSet, labels, featLabels)print(myTree) 递归创建决策树时递归有两个终止条件第一个停止条件是所有的类标签完全相同则直接返回该类标签第二个停止条件是使用完了所有特征仍然不能将数据划分仅包含唯一类别的分组即决策树构建失败特征不够用。此时说明数据纬度不够由于第二个停止条件无法简单地返回唯一的类标签这里挑选出现数量最多的类别作为返回值。
运行上述代码我们可以看到如下结果 3.使用决策树执行分类 依靠训练数据构造了决策树之后我们可以将它用于实际数据的分类。在执行数据分类时需要决策树以及用于构造树的标签向量。然后程序比较测试数据与决策树上的数值递归执行该过程直到进入叶子结点最后将测试数据定义为叶子结点所属的类型。在构建决策树的代码可以看到有个featLabels参数。它是用来干什么的它就是用来记录各个分类结点的在用决策树做预测的时候我们按顺序输入需要的分类结点的属性值即可。举个例子比如我用上述已经训练好的决策树做分类那么我只需要提供这个人是否有房子是否有工作这两个信息即可无需提供冗余的信息。
用决策树做分类的代码很简单编写代码如下
# -*- coding: UTF-8 -*-
from math import log
import operatordef calcShannonEnt(dataSet):numEntires len(dataSet) #返回数据集的行数labelCounts {} #保存每个标签(Label)出现次数的字典for featVec in dataSet: #对每组特征向量进行统计currentLabel featVec[-1] #提取标签(Label)信息if currentLabel not in labelCounts.keys(): #如果标签(Label)没有放入统计次数的字典,添加进去labelCounts[currentLabel] 0labelCounts[currentLabel] 1 #Label计数shannonEnt 0.0 #经验熵(香农熵)for key in labelCounts: #计算香农熵prob float(labelCounts[key]) / numEntires #选择该标签(Label)的概率shannonEnt - prob * log(prob, 2) #利用公式计算return shannonEnt #返回经验熵(香农熵)def createDataSet():dataSet [[0, 0, 0, 0, no], #数据集[0, 0, 0, 1, no],[0, 1, 0, 1, yes],[0, 1, 1, 0, yes],[0, 0, 0, 0, no],[1, 0, 0, 0, no],[1, 0, 0, 1, no],[1, 1, 1, 1, yes],[1, 0, 1, 2, yes],[1, 0, 1, 2, yes],[2, 0, 1, 2, yes],[2, 0, 1, 1, yes],[2, 1, 0, 1, yes],[2, 1, 0, 2, yes],[2, 0, 0, 0, no]]labels [年龄, 有工作, 有自己的房子, 信贷情况] #特征标签return dataSet, labels #返回数据集和分类属性def splitDataSet(dataSet, axis, value): retDataSet [] #创建返回的数据集列表for featVec in dataSet: #遍历数据集if featVec[axis] value:reducedFeatVec featVec[:axis] #去掉axis特征reducedFeatVec.extend(featVec[axis1:]) #将符合条件的添加到返回的数据集retDataSet.append(reducedFeatVec)return retDataSet #返回划分后的数据集def chooseBestFeatureToSplit(dataSet):numFeatures len(dataSet[0]) - 1 #特征数量baseEntropy calcShannonEnt(dataSet) #计算数据集的香农熵bestInfoGain 0.0 #信息增益bestFeature -1 #最优特征的索引值for i in range(numFeatures): #遍历所有特征#获取dataSet的第i个所有特征featList [example[i] for example in dataSet]uniqueVals set(featList) #创建set集合{},元素不可重复newEntropy 0.0 #经验条件熵for value in uniqueVals: #计算信息增益subDataSet splitDataSet(dataSet, i, value) #subDataSet划分后的子集prob len(subDataSet) / float(len(dataSet)) #计算子集的概率newEntropy prob * calcShannonEnt(subDataSet) #根据公式计算经验条件熵infoGain baseEntropy - newEntropy #信息增益# print(第%d个特征的增益为%.3f % (i, infoGain)) #打印每个特征的信息增益if (infoGain bestInfoGain): #计算信息增益bestInfoGain infoGain #更新信息增益找到最大的信息增益bestFeature i #记录信息增益最大的特征的索引值return bestFeature #返回信息增益最大的特征的索引值def majorityCnt(classList):classCount {}for vote in classList: #统计classList中每个元素出现的次数if vote not in classCount.keys():classCount[vote] 0 classCount[vote] 1sortedClassCount sorted(classCount.items(), key operator.itemgetter(1), reverse True) #根据字典的值降序排序return sortedClassCount[0][0] #返回classList中出现次数最多的元素
def createTree(dataSet, labels, featLabels):classList [example[-1] for example in dataSet] #取分类标签(是否放贷:yes or no)if classList.count(classList[0]) len(classList): #如果类别完全相同则停止继续划分return classList[0]if len(dataSet[0]) 1 or len(labels) 0: #遍历完所有特征时返回出现次数最多的类标签return majorityCnt(classList)bestFeat chooseBestFeatureToSplit(dataSet) #选择最优特征bestFeatLabel labels[bestFeat] #最优特征的标签featLabels.append(bestFeatLabel)myTree {bestFeatLabel:{}} #根据最优特征的标签生成树del(labels[bestFeat]) #删除已经使用特征标签featValues [example[bestFeat] for example in dataSet] #得到训练集中所有最优特征的属性值uniqueVals set(featValues) #去掉重复的属性值for value in uniqueVals: #遍历特征创建决策树。 myTree[bestFeatLabel][value] createTree(splitDataSet(dataSet, bestFeat, value), labels, featLabels)return myTreedef classify(inputTree, featLabels, testVec):firstStr next(iter(inputTree)) #获取决策树结点secondDict inputTree[firstStr] #下一个字典featIndex featLabels.index(firstStr) for key in secondDict.keys():if testVec[featIndex] key:if type(secondDict[key]).__name__ dict:classLabel classify(secondDict[key], featLabels, testVec)else: classLabel secondDict[key]return classLabelif __name__ __main__:dataSet, labels createDataSet()featLabels []myTree createTree(dataSet, labels, featLabels)testVec [0,1] #测试数据result classify(myTree, featLabels, testVec)if result yes:print(放贷)if result no:print(不放贷) 用决策树分类。输入测试数据[0,1]它代表没有房子但是有工作分类结果如下所示 总结
优点
易于理解和解释。决策树可以可视化。几乎不需要数据预处理。其他方法经常需要数据标准化创建虚拟变量和删除缺失值。决策树还不支持缺失值。使用树的花费例如预测数据是训练数据点(data points)数量的对数。可以同时处理数值变量和分类变量。其他方法大都适用于分析一种变量的集合。可以处理多值输出变量问题。使用白盒模型。如果一个情况被观察到使用逻辑判断容易表示这种规则。相反如果是黑盒模型例如人工神经网络结果会非常难解释。即使对真实模型来说假设无效的情况下也可以较好的适用。
缺点
决策树学习可能创建一个过于复杂的树并不能很好的预测数据。也就是过拟合。修剪机制现在不支持设置一个叶子节点需要的最小样本数量或者数的最大深度可以避免过拟合。决策树可能是不稳定的因为即使非常小的变异可能会产生一颗完全不同的树。这个问题通过decision trees with an ensemble来缓解。概念难以学习因为决策树没有很好的解释他们例如XOR, parity or multiplexer problems。如果某些分类占优势决策树将会创建一棵有偏差的树。因此建议在训练之前先抽样使样本均衡。