决策树是一种基于树结构,使用层层推理来解决分类(回归)问题的算法
决策树由下面几种元素构成:
决策树模型的三个步骤
根据特征选择不同方法有三种经典的决策树算法:ID3、C4.5、CART
特征选择的目标:决策树分类的目标就是让同类样本最终在同一叶节点中,不同类最终在不同叶节点中,所以在划分过程中,我们希望决策树的分支节点所包含的样本尽可能属于同一类别,即节点的“纯度”越来越高。
采用信息增益作为特征选择的方法。“信息熵”是度量样本纯度的常用的一种指标信息熵越小,纯度越高。
有 G a i n ( D , a ) Gain(D,a) Gain(D,a)可知,信息增益越大,使用属性a来进行划分得到纯度提升越大,所以我们选择信息增益最大的属性来进行划分。
使用信息增益来进行特征选择一个缺点是:该方法对数目较多的属性有所偏好。
C4.5算法采用信息增益率作为特征选择的方法,此方法正是为了解决信息增益准则对可取值较多的属性有所偏好的不利影响。
但遗憾的是,采用欣喜增益率准也有缺点:对可取值较少的属性有所偏好。
CART采用基尼指数作为特征选择的方法。
基尼指数表示在数据集中随机抽取两个样本,他们类别不一致的概率,很明显,基尼指数越小,即随机抽取的两个样本类别不一致的概率越小,类别一致的概率就越高,那么纯度就越高。采用基尼指数也减少了大量的对数运算。
另外,CART可以用于回归任务。
剪枝处理是决策树算法解决过拟合的主要手段,基本策略有:
预剪枝:在决策树生成过程中,对每个进行划分前先进行估计,如果不能带来决策树泛化能力的提升,则停止划分并将当前结点标记为叶节点。预剪枝也带了“欠拟合的风险。后剪枝:先生成一颗完整的决策树,然后自底而上的对非叶结点进行考察,若将该结点替换成叶结点能带泛化能力的提升,则将该子树替换成叶结点。时间开销大于预剪枝。ID3算法没有剪枝策略,
根据衡量泛化能力的方法有很多不同策略的剪枝,ID3算法采用悲观剪枝策略,CART采用代价复杂度剪枝策略。
**代价复杂度剪枝(后剪枝)**主要包含以下两个步骤:
从完整决策树 T 0 T_0 T0开始,生成一个子树序列${T_0,T_1,…,T_n},其中 T ( i + 1 ) T_(i+1) T(i+1) 由 T i T_i Ti 生成, T n T_n Tn为根结点。1. 如何在特征值缺失的情况下进行划分特征的选择?
2. 选定该划分特征,模型对于缺失该特征值的样本该进行怎样处理?
CART采取的机制是代理分裂,即如果某个存在缺失值的特征是当前最佳的分裂特征,那么我们需要遍历剩余所有特征,选择能与最佳增益的缺失特征分裂之后增益最接近的特征进行分裂,剩余特征中如果也存在缺失值,那这些特征也忽略。选定划分特征之后,当前缺失该特征的样本划分到左右子树取决于代理特征。这种处理缺失值的方法,需要遍历其他所有特征代价太大。Sklearn中决策树模型没有缺失值的处理。
C4.5处理缺失值的方法,是通过计特征上未缺失值的样本的信息增益,然后加上个未缺失样本的权重,选择划分特征之后,对于缺失特征值的样本,让该样本以不同概率划分到不同的节点中去。
决策树的优点:
1、计算复杂度不高,输出结果易于理解,
2、对中间值的缺失不敏感(CART、C4.5),比较适合处理有缺失属性的样本
3、可以处理不相关特征数据。
4、可以同时处理标称型和数值型数据
缺点:
1、容易过拟合
2、容易忽略数据集中属性的相互关联
3、使用信息增益和CART的决策树对可取数目较多的属性有所偏好,使用信息增益率对可取值较少的属性有所偏好。
除了特征选择,剪枝处理的差异之外,还可以从以下角度来考虑三者之间的差异。
从应用角度,ID3和C4.5只能用于分类任务,而CART(Classification and Regression Tree,分类回归树)从名字就可以看出其不仅可以用于分类,也可以应用于回归任务(回归树使用最小平方误差准则)从样本类型的角度,ID3只能处理离散型变量,而C4.5和CART都可以处理连续型变量。C4.5处理连续型变量时,通过对数据排序之后找到类别不同的分割线作为切分点,根据切分点把连续属性转换为布尔型,从而将连续型变量转换多个取值区间的离散型变量。而对于CART,由于其构建时每次都会对特征进行 二值划分,因此可以很好地适用于连续性变量。从实现细节、优化过程等角度,这三种决策树还有一些不同。比如,ID3对样本特征缺失值比较敏感,而C4.5和CART可以对缺失值进行不同方式的处理;ID3和C4.5可以在每个结点上产生出多叉分支,且每个特征在层级之间不会复用,而CART每个结点只会产生两个分支,因此最后会形成一颗二叉树,且每个特征可以被重复使用;ID3和C4.5通过剪枝来权衡树的准确性与泛化能力,而CART直接利用全部数据发现所有可能的树结构进行对比。CART回归树和CART分类树的建立算法大部分都是类似的,所以我们这里只讨论CART回归树和CART分类树之间的建立算法的不同。
回归树和分类树的最主要区别在于样本输出,如果样本输出是离散值,那么这是一颗分类树,如果样本输出是连续值,那么这是一颗回归树。
除了概念上的不同之外,CART回归树和CART分类树的建立和预测的其区别主要有下面两点:
连续值的处理不同:确定特征以及特征值的划分点不同。决策树建立之后做预测的方式不同对于连续值的处理,CART分类时是基于基尼系数的大小来度量特征的各个划分点的优劣情况。这比较适合分类树,对于回归模型,我们知道最常用的度量方式是均方误差,这里回归树采用的是和方差的度量方式,对于任意划分特征A,对应的任意划分点s两边划分成的数据集D1和D2,求出使D1和D2各自集合的均方差最小,同时D1和D2的均方差之和最小对应的特征和特征值划分点。表达式为:
对于决策树建立后做预测的方式,上面讲到了CART分类树采用叶子节点里概率最大的类别作为当前节点的预测类别。而回归树输出不是类别,它采用的是用最终叶子的均值或者中位数来预测输出结果。
除了上面提到了以外,CART回归树和CART分类树的建立算法和预测没有什么区别。
优点:
简单直观,相比较于神经网络之类的黑盒模型,决策树逻辑上可以得到很好的解释。基本不需要数据预处理,不需要提前归一化,处理缺失值。使用决策树预测代价是O(log2m)。m为样本数既可以处理离散值也可以处理连续。可以处理多维度输出的分类问题。叶子结点做多分类。对异常点的容错能力好,健壮性高缺点:
决策树非常容易过拟合,导致泛化能力不强,可以通过剪枝,设置节点最小样本数量和限制树的深度来改进,决策树回因为样本一点点变动,就会导致树结构的剧烈改变,这个可以通过集成学习的方法来改进。模型的表达能力有限。如果某些特征的样本比例过大,生成决策树容易偏向于这些特征。这个可以通过调节样本权重来改善。""" 伪代码: creteBranch函数 检测数据集中的每个子项是否属于同一分类: if so return 类标签; else 寻找划分数据集的最好特征 划分数据集 创建分支节点 for 每个划分子集 调用函数createBranch并增加返回结果到分支节点中 return 分支节点 """ from math import * import operator class Tree: def clacShannonEnt(self, dataset): """ 计算香浓熵的函数 :param dataset:数据集 :return: 香浓熵的值 """ numEntries = len(dataset) labelCounts = {} for featVec in dataset: currentLabel = featVec[-1] labelCounts[currentLabel] = labelCounts.get(currentLabel, 0)+1 shannonEnt = 0.0 for key in labelCounts: prob = float(labelCounts[key])/numEntries shannonEnt -= prob*log(prob, 2) return shannonEnt def splitDataSet(self,dataset, axis, value): """ 按照给定特征划分数据集 :param dataset: 待划分数据集 :param axis: 待划分数据集特征索引 :param value: 需要返回的特征的值 :return: """ retDataSet = [] for featVec in dataset: if featVec[axis] == value: reduceFeatVec = featVec[:axis] reduceFeatVec.extend(featVec[axis+1:]) retDataSet.append(reduceFeatVec) return retDataSet def chooseBestFeatureToSplit(self,dataset): """ 选择最好的数据集划分方式 :param dataset: 数据集 :return: 最好的划分特征 """ numFeatures = len(dataset[0]) - 1 bestEntropy = self.clacShannonEnt(dataset) bestInfoGain = 0.0 bestFeature = -1 for i in range(numFeatures): featList = [example[i] for example in dataset] uniqueVals = set(featList) newEntropy = 0.0 for value in uniqueVals: subDataSet = self.splitDataSet(dataset, i, value) prob = len(subDataSet)/float(len(dataset)) newEntropy += prob*self.clacShannonEnt(subDataSet) infoGain = bestEntropy-newEntropy if (infoGain>bestInfoGain): bestInfoGain = infoGain bestFeature = i return bestFeature def majorityCnt(self, classList): """ 多数投票法 :param classList:分类名称的列表 :return: 返回出现次数最多的类 """ classCount = {} for vote in classList: classCount[vote] = classCount.get(vote, 0) + 1 sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) return sortedClassCount[0][0] def createTree(self, dataset, labels): """ 创建树的函数代码 :param dataset: 数据集 :param labels: 标签列表 :return: 决策树 """ classList = [example[-1] for example in dataset] #print(classList) #递归终止条件 if classList.count(classList[0]) == len(classList): return classList[0] if len(dataset[0])==1: return self.majorityCnt(classList) bestFeat = self.chooseBestFeatureToSplit(dataset) bestFeatLabel = labels[bestFeat] myTree = {bestFeatLabel:{}} del(labels[bestFeat]) featValue = [example[bestFeat] for example in dataset] uniqueVals = set(featValue) for value in uniqueVals: subLabels = labels[:] myTree[bestFeatLabel][value] = self.createTree(self.splitDataSet(dataset, bestFeat, value) , subLabels) return myTree def classify(self, inputTree, featLabels, testVec): global classLabel firstStr = list(inputTree.keys())[0] # print(featLabels) # print(firstStr) secondDict = inputTree[firstStr] featIndex = featLabels.index(firstStr) #print(featIndex) for key in secondDict.keys(): print(key) if testVec[featIndex] == key: if type(secondDict[key]).__name__=='dict': classLabel = self.classify(secondDict[key],featLabels,testVec) else: classLabel = secondDict[key] return classLabel if __name__ == "__main__": dataset = [[1,1,'yes'], [1,1,"yes"], [1,0,'no'], [0,1,'no'], [0,1,'no']] labels = ["no surfacing", "fileters"] #print(labels.index("no surfacing")) tree = Tree() myTree = tree.createTree(dataset, labels) print(myTree) a = tree.classify(myTree,["no surfacing", "fileters"], [1,0]) print("leibie",a)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143'相关知识
python利用c4.5决策树对鸢尾花卉数据集进行分类(iris)
分类算法3:决策树及R语言实现
决策树分类器(保姆级教学) 定义+特性+原理及公式+鸢尾花分类经典问题示例(完整Python代码带详细注释、保姆级分部代码解释及结果说明、决策树可视化及解释)
【python数据挖掘课程】十九.鸢尾花数据集可视化、线性回归、决策树花样分析
花草 python
从用户需求到产品设计:如何实现有效的人机交互
【机器学习】R语言实现随机森林、支持向量机、决策树多方法二分类模型
智能农业的植物病虫害预警系统:如何保护农业产品
人工智能与客户关系管理:如何实现高效的客户资源利用
以鸢尾花数据集为例,用Python对决策树进行分类
网址: 决策树python实现及常见问题总结 https://m.huajiangbk.com/newsview1356576.html
上一篇: 金钱木养多长时间会开花?(已有7 |
下一篇: 关于二叉树的22个常见问题 |