决策树

来源:互联网 发布:最新网络术语 编辑:程序博客网 时间:2024/06/05 18:46

一.创建分支的伪代码函数createBranch()如下所示:

If so return 类标签:Else    寻找划分数据集的最好特征    创分数据集    创建分支节点       for 每个划分的子集           调用函数createBranch()并增加返回结果到分支节点中       return  分支节点**其实createBranch是一个递归函数,在倒数第二行调用了自己**

二.信息论——信息增益

划分数据集的大原则是:将无序的数据变得更加有序。我们可以使用多种方法划分数据集。组织杂乱无章数据的一种方法就是使用信息论度量信息,信息论是量化处理信息的分支科学。我们可以在划分数据之前使用信息论量化度量信息的内容。

在划分数据集之前之后信息发生的变化称为信息增益,计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。 (划分的依据是取得获得信息增益最高的)

熵定义为信息的期望值,那么信息的定义又是什么:如果待分类的事务可能划分在多个分类之中,则信息的定义:x_{i}=-log_{2}p(x_{i}) 这里的 p(x_{i}) 指的是选择该类的概率

则熵:H=-\sum_{i=1}^{n}p(x_{i})log_{2}p(x_{i}),其中n代表的是选择的类别,即类别的总数

1.计算香农熵:

from math import log   #导入对数函数def shanNonEnt(dataset):    numentries=len(dataset)       labelcounts={}  #创建一个空字典    for featvec in dataset:  #dataset是列表        currenlabel=featvec[-1] #将featvec的最后一个元素提取        if currenlabel not in labelcounts.keys():             labelcounts[currenlabel]=1  #若此时的label在labelcounts没有,则赋值为1        else:            labelcounts[currenlabel] +=1  #如果有,则加1    shannonEnt=0.0    for key in labelcounts:        prob=float(labelcounts[key])/numentries  #计算概率        shannonEnt -=prob*log(prob,2)  #计算香农    return shannonEntdef createdataset(): #自己弄个数据集呗    dataset=[[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no']]     return dataset

结果输出为:

>>> import tree>>> reload(tree)<module 'tree' from 'tree.pyc'>>>> dataset=tree.createdataset()>>> tree.shanNonEnt(dataset)0.9709505944546686

如果我们不断的向产生的数据集里添加标签,情况会是怎么样呢,如下:

def createdataset():    dataset=[[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no'],[2,1,'maybe']]  #多添加一个类别    return datasetoutput:1.4591479170272448def createdataset():    dataset=[[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no'],[2,1,'maybe'],[1,0,'haha']]    return datasetoutput:1.8423709931771086

从上述可以看到,当数据集中的类别越多的时候,香农熵越来越大

2.划分数据集
分类算法除了需要测量信息熵,还需要划分数据集,度量划分数据集的熵,以便判断是否正确划分了数据集。我们将对每个特征划分数据集的结果计算一次信息熵,然后判断按照哪个特征划分数据集是最好的划分方式。程序如下:

def splitDataSet(dataset,axis,value):#待划分的数据集,划分数据集的特征、特征的返回值    retDataSet=[]    for featVec in dataset:  #取出一组数据的所有特征,是一个列表        if featVec[axis]==value:  #当选中的那一个特征刚好等于我们指定的特征的时候            reducedFeatVec=featVec[:axis] #对axis前面的元素赋值给reducedFeatVec            reducedFeatVec.extend(featVec[axis+1:])  #将axis后面的元素赋值给reducedFeatVec            retDataSet.append(reducedFeatVec)    return retDataSet

输出:

>>> import tree>>> reload(tree)<module 'tree' from 'tree.pyc'>>>> dataset=tree.createdataset()>>> tree.splitDataSet(dataset,1,1)[[1, 'yes'], [1, 'yes'], [0, 'no'], [0, 'no'], [2, 'maybe']]

在上述的例子中,我们需要注意的是list.append 和 list.extend这个俩个函数的区别:尽管在大多数情况下这俩个函数具有很相似的特征,但是对于俩个列表而言,却是不一样的:

>>> a=[1,2,3]>>> b=[2,3,4]>>> a.extend(b) #将列表b的元素拆开,逐个赋值给a>>> a[1, 2, 3, 2, 3, 4]>>> a=[1,2,3]>>> b=[2,3,4]>>> a.append(b)>>> a[1, 2, 3, [2, 3, 4]]  #这里是将列表b当做一个元素赋值到a中

3.循环计算香农熵和splitDataSet()函数

def chooseBestFeatureToSplit(dataset):      numfeature=len(dataset[0])-1  #所有特征类别的数目    baseEntropy=shanNonEnt(dataset)  #计算香农熵,这里计算的香农熵是用最后一个标签来计算的    bestinfoGain=0.0;bestfeature=-1    for i in range(numfeature):  #循环所有的特征        featList=[example[i] for example in dataset]  #将同一类特征的所有取值放到一个list表中        uniqueval=set(featList)        newEntropy=0.0        for value in uniqueval:  #对于同一类特征中的不同取值            subdataset=splitDataSet(dataset,i,value)            pro=len(subdataset)/float(len(dataset))  #取得该特征的概率            newEntropy +=pro*shanNonEnt(subdataset)  #算出按照这个特征分类的香农熵        infoGain=baseEntropy-newEntropy      #算出信息增益,香农熵的变化        if(infoGain>bestInforGain):  #比较不同特征算出来的信息增益,信息增益大的较好,即为要求的特征            bestinfoGain=infoGain            bestFeature=i    return bestFeature    
原创粉丝点击