机器学习第二篇:决策树算法

决策树的基础部分还是很简单易懂的,但是剪枝处理和多决策问题我现在还没有接触到。我也是个初学者,从初学者角度写的,大佬就绕道了吧。

我们决策树的划分都是建立在熵的基础之上的,首先是熵的计算公式:

                                                         -\sum p_k log_2 p_k  (其中k是我们的种类编号)

然后还有一个很重要的概念--信息增益:

                                                        Gain(D,a) = Ent(D) - \sum \frac{D^{v}}{D}Ent(D^{v})

其中v表示a这种属性的第v个类别,其中信息增益越大越好,最大的做为我们的划分属性。

不需要划分的三种情况:

(1)当前节点包含的样本全属于同一类别;

(2)当前属性集为空,或是所有样本在所有属性上取值相同,无法划分;

(3)当前节点包含的样本集合为空,不能划分

注意(2)(3)的区别,(2)是把当前节点标记为叶节点,并将其类别设定为该节点所含样本最多的类别,(3)同意把当前节点标记为叶节点,但将其类别设定为其父节点所含样本最多的类别。这两种清醒的处理实质不同,(2)是利用当前节点的后验分布,(3)把父节点的样本分布作为当前节点的先验分布。

之后我们就基于这两个公式开始我们的决策

从网上找了一组数据来做为样例:

然后我们就使用上面的数据,并选择活动这列做为我们的划分目标,那么我们就开始第一步 计算我们的信息熵:

def calcShannonEnt(dataSet):#计算信息熵
    numEntries = len(dataSet)
    
    labelCounts = {}
    for featVec in dataSet:    #读取dataset当中的每一行
        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
        shannonEnt -= prob*log(prob,2) #导入math库
        
return shannonEnt

整个实现过程就是按照公式一步一步写出来的,不懂得可以留言哈

然后对每个属性都计算他们的信息增益,将最大的信息增益作为我们的划分属性,求解每个属性的信息增益按照我们上面的公式计算。

#分成两部分第一个函数splitdata是负责把我们需要的属性类别专门提取出来,就比如先算天气中的晴天,就把晴天那几行挑选出来
#第二个函数是负责挑选属性及属性值分别放到splitdata当中来计算。
def splitDataSet(dataSet,axis,value):
    retDataSet = []
    for featVec in dataSet:#取大列表中的每个小列表
        if featVec[axis]==value:
            reduceFeatVec=featVec[:axis]
            reduceFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reduceFeatVec)
    
    return retDataSet #返回不含划分特征的子集
    
def chooseBestFeatureToSplit(dataSet):
    numFeature = len(dataSet[0]) - 1
    baseEntropy = calcShannonEnt(dataSet)
    bestInforGain = 0
    bestFeature = -1
    
    for i in range(numFeature):
        featList = [number[i] for number in dataSet]#得到某个属性下所有值(某列)
        uniquelVals = set(featList) #set无重复的属性特征值,得到所有无重复的属性取值
        
        #计算每个属性i的概论熵
        newEntropy = 0
        for value in uniquelVals:
            subDataSet = splitDataSet(dataSet,i,value)#得到i属性下取i属性为value时的集合
            prob = len(subDataSet)/float(len(dataSet))#每个属性取值为value时所占比重
            newEntropy+= prob*calcShannonEnt(subDataSet)
        inforGain = baseEntropy - newEntropy #当前属性i的信息增益
        
        if inforGain>bestInforGain:
            bestInforGain = inforGain
            bestFeature = i
   
return bestFeature#返回最大信息增益属性下标

上面这个函数大致的意思是:比如第一次先选择天气,然后把天气中的类别晴、阴、雨放在一个集合当中,然后把他们分别拿出来,第一次拿晴天,把晴天这个值带入到splitdata当中,把晴天对应的几行数据挑出来,然后计算信息增益的。

之后把最大的信息增益作为我们的划分属性,然后在划分属性的基础之上,在寻找最大增益。

之后就要构造决策树了:

#递归创建树,用于找出出现次数最多的分类名称
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)
    #classcount.items 返回的是(key,value)组成的列表,key=operator.itemgetter(1),是一个临时函数,访问第()域,这里访问的就是value,按照value的大小来排序,注意导入包operator
    return sortedClassCount[0][0]


def createTree(dataSet,labels):
    classList=[example[-1] for example in dataSet]#创建数组存放所有标签值,取dataSet里最后一列(结果)
    #类别相同,停止划分
    if classList.count(classList[-1])==len(classList):#判断classList里是否全是一类,count() 方法用于统计某个元素在列表中出现的次数
        return classList[-1] #当全是一类时停止分割
    #长度为1,返回出现次数最多的类别
    if len(classList[0])==1: #当没有更多特征时停止分割,即分到最后一个特征也没有把数据完全分开,就返回多数的那个结果
        return majorityCnt(classList)
    #按照信息增益最高选取分类特征属性
    bestFeat=chooseBestFeatureToSplit(dataSet)#返回分类的特征序号,按照最大熵原则进行分类
    bestFeatLable=labels[bestFeat] #该特征的label, #存储分类特征的标签
    
    myTree={bestFeatLable:{}} #构建树的字典
    del(labels[bestFeat]) #从labels的list中删除该label
    
    featValues=[example[bestFeat] for example in dataSet]
    uniqueVals=set(featValues)
    for value in uniqueVals:
        subLables=labels[:] #子集合 ,将labels赋给sublabels,此时的labels已经删掉了用于分类的特征的标签
        #构建数据的子集合,并进行递归
        myTree[bestFeatLable][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLables)
return myTree

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值