机器学习实战之决策树

来源:互联网 发布:ccf工资计算c语言实现 编辑:程序博客网 时间:2024/05/11 20:24

1 算法概述
1.1 结构分析
决策树是一种依托决策而建立起来的树,其中,每一个内部节点表示一个属性上的测试,每一个分支代表一个测试的结果输出,每一个叶子代表一种类别。
这里写图片描述
如上图所示就是一个决策树,首先分析所给数据集是否为同一类别,如果是,那就不用划分了,如果不是,就寻找划分数据集最好的特征进行划分(也就是影响数据集划分因素最明显的特征划分,这个后面会专门介绍最大信息增益法划分,知道怎么用就中),比如上图一开始就是选择的是:发送邮件域名地址为某某莫,每个内部节点(数据子集)代表一个二分类问题,每个叶子节点是分类的结果,遇到内部节点就一直划分,直到划分的数据子集都属于同一类型的数据时,就停止划分,此时,也就意味着你的决策树已经建好。
1.2 算法思想
这是一种寻找数据集内部之间规律的算法,以信息熵为度量,构造一颗熵值下降最快的数,到叶子节点处的熵值为零。此时,每一个叶子代表一个类别。
在决策树的每一个非叶子结点划分之前,先计算每一个属性所带来的信息增益,选择最大信息增益的属性来划分,因为信息增益越大,区分样本的能力就越强,越具有代表性,很显然这是一种自顶向下的贪心策略。以上就是ID3算法的核心思想
1.3 算法实现步骤
①计算每种特征划分方式的信息熵,选取信息熵最大的一种划分方式
②递归的构建决策树
2 实现
(1)创造数据集
(2)计算数据集信息熵

def calcShannonEnt(dataSet):    numEntries = len(dataSet) #len()是计算变量长度的函数 ,numEntries=5    labelCounts = {}   #为所有可能分类创造字典    #遍历每条数据集样本,如果字典里没有数据集中的类别,将此类别存入字典中,如果有,将此类别数目加1    #以下for循环里计算结果为labelCounts=['yes':2,'no':3]    #其实,以下for循环可以用一句话概括:    #labelCounts[currentLabel]=labelCounts.get(currentLabel,0)+1    for featVec in dataSet: #the the number of unique elements and their occurance        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 #numEntries=5        shannonEnt -= prob * log(prob,2) #log base 2    return shannonEnt

(3)根据上面计算的信息熵,划分数据集
(4)选择最好的划分结果

def chooseBestFeatureToSplit(dataSet):    numFeatures = len(dataSet[0]) - 1      #特征数,-1是因为dataSet最后一列是标签类别    baseEntropy = calcShannonEnt(dataSet)   #计算总数据集的信息熵    bestInfoGain = 0.0; bestFeature = -1    for i in range(numFeatures):        #遍历每一个特征        featList = [example[i] for example in dataSet]#遍历每个特征的数据集        uniqueVals = set(featList)    #第i个特征取值集合,如果i=1,则uniqueVals=[1,1,1,0,0]        newEntropy = 0.0        for value in uniqueVals: #依据特征划分数据集,并计算每种划分方式的信息熵            subDataSet = splitDataSet(dataSet, i, value)            prob = len(subDataSet)/float(len(dataSet))            newEntropy += prob * calcShannonEnt(subDataSet)             infoGain = baseEntropy - newEntropy     #calculate the info gain; ie reduction in entropy        if (infoGain > bestInfoGain):       #选择最大信息熵的划分结果            bestInfoGain = infoGain         #if better than current best, set to best            bestFeature = i    return bestFeature                      #returns an integer

(5)递归构造决策树
多数表决的方法决定叶子节点的分类 –该叶子属于哪一类的样本最多,我们就说该叶子属于哪类

def createTree(dataSet,labels):    classList = [example[-1] for example in dataSet] #数据集所有标签列表    #终止条件1;类别完全相同,表示就只有一个类别,则停止继续划分  返回标签-叶子节点    if classList.count(classList[0]) == len(classList):        return classList[0]#stop splitting when all of the classes are equal    #终止条件2:无法将数据集划分成唯一类别时,采用多数表决法决定叶子的分类    if len(dataSet[0]) == 1: #stop splitting when there are no more features in dataSet        return majorityCnt(classList)  #遍历完所有的特征时返回出现次数最多的    #开始创建树    bestFeat = chooseBestFeatureToSplit(dataSet) #选择最好的方式进行划分数据集,得到最好划分数据集特征    bestFeatLabel = labels[bestFeat]    myTree = {bestFeatLabel:{}}  #用上面得到的最好划分数据集特征建立一个空树(空字典)    del(labels[bestFeat])  #删除labels[bestFeat]    featValues = [example[bestFeat] for example in dataSet]    uniqueVals = set(featValues)    for value in uniqueVals:  #遍历当前选择的特征包含的所有属性        subLabels = labels[:]       #copy all of labels, so trees don't mess up existing labels        #递归调用构建树的过程,直到遍历完所有划分数据集属性,所有相同类别的数据均被分到同一个数据子集中        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)    return myTree

(6)用决策树进行预测标签

def classify(inputTree,featLabels,testVec):    firstStr = inputTree.keys()[0] #第一个特征属性:firstStr='no surfacing'    #除去第一个特征属性的字典:secondDict={0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}    secondDict = inputTree[firstStr]    featIndex = featLabels.index(firstStr) #寻找第一个特征属性在特征属性列表中的位置:featIndex=0    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 classLabel
0 0
原创粉丝点击