Quo的随手笔记之决策树

    技术2025-02-26  17

    决策树算法

    算法的介绍决策树思想阐述

    算法的介绍

    决策树是一种监督学习算法,之前大火的小爱同学猜人名就是用这样的算法实现,通过不停的询问,即不停的分类,最终到无法进行分类的时候就锁定了结果。现实中有诸多应用,比如植物、动物的分类,本博客中的决策树分类方法叫做ID3,除此之外主流决策树算法还有CART和C4.5等

    参考文献:《Machine Learning in Action》,知乎百科

    决策树思想阐述

    用官方的话来说,决策树是一个预测模型;他代表的是对象属性与对象值之间的一种映射关系。树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每个叶结点则对应从根节点到该叶节点所经历的路径所表示的对象的值。 要想了解决策树的意义,首先要了解什么是熵, 香农熵, 对于任意一个随机变量 X,它的熵定义如下: 变量的不确定性越大,熵也就越大,把它搞清楚所需要的信息量也就越大。

    具体定义请参考:https://blog.csdn.net/theonegis/article/details/79890407 目标: 为了分辨一种物种是否为鱼类,实验人员收集了一组数据,希望能够从中找出分类的依据,帮忙判断新的物种是否能被认为是鱼类。 数据集如下

    鳞片鳍是否是鱼类有有是有有是无有否有无否无有否

    1计算熵,代码如下

    // By Quo &Peter Harrington from math import log import operator #计算熵 def calculateEntropy(dataSet) : numEntries=len(dataSet) labelCounts={} #对于结构性数据进行分类的数目统计 for featVec in dataSet : #对于每一行的最后一列数据进行类别的统计 currentLabel=featVec[-1] if currentLabel not in labelCounts: labelCounts[currentLabel]=0 labelCounts[currentLabel]+=1 Entropy=0 for key in labelCounts: #本选项被选择的概率 prob=float(labelCounts[key])/numEntries #对于每一项不重复的key进行熵的求和(因为分数进行对数运算之后是负数,所以就是求减) Entropy= Entropy-prob*log(prob,2) return Entropy def createDateSet(): #构建初始数据 dataSet=[[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no']] labels =['no surfacing','flippers'] return dataSet,labels

    2.选取最优熵 因为不同维度的分类的熵是不一样的,所以我们需要选出熵最大的进行优先筛选,代码如下

    #选择最好的分类方式 def chooseBestFeature2Split(dataSet): numFeatures=len(dataSet[0])-1 baseEntropy=calculateEntropy(dataSet) bestInfoGain=0 bestFeature=0 for i in range(numFeatures): #分别对每一列进行分类操作之后求信息期望值, featList=[example[i] for example in dataSet] #取得第i列的数据变成一个list uniqueValues=set(featList) #去重 得到值域 newEntropy=0 for value in uniqueValues: subdataSet=splitDataSet(dataSet,i,value) prob=len(subdataSet)/float(len(dataSet)) newEntropy=newEntropy+prob*calculateEntropy(subdataSet) #以上为计算信息期望值的公式,即每一个选项被选中的概率乘以熵的总和 infoGain=baseEntropy-newEntropy if(infoGain >bestInfoGain): baseEntropy=infoGain bestFeature=i #以上为判断大小,信息期望值越大,就代表是更好的数据集的划分方式 return bestFeature #返回的为列的标号 对单条件进行分类 即得到最优解的标号之后,拿出此列作为分类依据并在数据集中去除此列,以便于下次分类 #用以去除每一行中特定列符合要求的值 def splitDataSet(dataSet,axis,value): result=[] for featVec in dataSet: if featVec[axis] ==value: reducedFeatVec=featVec[:axis] reducedFeatVec.extend(featVec[axis+1:]) result.append(reducedFeatVec) return result 当分类到最后一个分支之后,还不能够将数据进行统一的分类,则返回剩下数据的频率比表示其可能性。 #用来对List中元素出现的频率进行排序 def majorityCnt(classList): classCount={} for vote in classList: if vote not in classCount.keys(): classCount[vote]=0 classCount[vote]+=1 sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) return sortedClassCount[0][0] 构造树,核心思想为,首先计算传入矩阵的不同维度的熵,取熵最大的一列数据并进行树结构的构造,根据取值来决定分支个数,然后去除本列数据,将剩余的矩阵进行递归处理,直至得到一个不可再分的矩阵并返回其树结构。

    python代码如下:

    // By Quo&Peter Harrington from math import log import operator # 决策树代码实例 def createTree(dataSet,labels): classList=[example[-1] for example in dataSet] #取最后一列为List if classList.count(classList[0])==len(classList): #如果第一行在数据中一直反复出现(即没有进行再次分类的必要了),则返回第一行 return classList[0] if len(dataSet[0])==1: #用来标识遍历结束时返回最多出现的类别 return majorityCnt(classList) bestFeature=chooseBestFeature2Split(dataSet) bestFeatLabel=labels[bestFeature] # 获取最高信息期望值的分类位置,和对应的标签 myTree={bestFeatLabel:{}} #得到标签之后构建树 del(labels[bestFeature]) #删除已使用的标签 featValues=[example[bestFeature] for example in dataSet] #提出最合适的分类列 uniqueVals=set(featValues) #去重,提取值域 for value in uniqueVals: subLabels=labels[:] myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeature,value),subLabels) #对于每一个值域中的值,树结构中新建结构 # 即对于和value匹配的数据,删除已用作分类的bestFeatLabel之后的结构 return myTree myData,label=createDateSet() print(createTree(myData,label))
    Processed: 0.010, SQL: 9