机器学习实战 决策树

时间:2022-12-20 11:56:24

这段时间太忙了,一直上课,作业也多,没来得及更新,早就打完的代码,一直没放上来,不行,以后一定要保持这个好习惯!!

今天讲下决策树,决策树也算是机器学习里面十分经典的算法了,最近参加数据挖掘比赛,发现基于决策树被广泛使用呀,像xgboost lightgbm gbdt等等,大放异彩,不过很多人都只会调用下函数(包括自己),要认真好好学才是呀!!!

1.决策树是一个预测模型;他代表的是对象属性与对象值之间的一种映射关系。树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每个叶结点则对应从根节点到该叶节点所经历的路径所表示的对象的值。决策树仅有单一输出,若欲有复数输出,可以建立独立的决策树以处理不同输出。 数据挖掘中决策树是一种经常要用到的技术,可以用于分析数据,同样也可以用来作预测

 1)树以代表训练样本的单个结点开始。
       2)如果样本都在同一个类.则该结点成为树叶,并用该类标记。
       3)否则,算法选择最有分类能力的属性作为决策树的当前结点.
       4)根据当前决策结点属性取值的不同,将训练样本数据集分为若干子集,每个取值形成一个分枝,有几个取值形成几个分枝。匀针对上一步得到的一个子集,重复进行先前  步骤,递4'I形成每个划分样本上的决策树。一旦一个属性出现在一个结点上,就不必在该结点的任何后代考虑它。
       5)递归划分步骤仅当下列条件之一成立时停止:
       ①给定结点的所有样本属于同一类。
       ②没有剩余属性可以用来进一步划分样本.在这种情况下.使用多数表决,将给定的结点转换成树叶,并以样本中元组个数最多的类别作为类别标记,同时也可以存放该结点样本的类别分布,
       ③如果某一分枝tc,没有满足该分支中已有分类的样本,则以样本的多数类创建一个树叶。

2.信息增益
对于决策树而言,划分的依据取决于信息熵划分数据集的大原则是 :将无序的数据变得有序。
组织杂乱无章数据的一种方法就是使用信息论度量信息,信息论是量化处理信息的分支科学。
在划分数据集之前之后的信息发生的变化称之为信息增益,知道如何计算信息增益,我们就可以计算每个特征的值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。
集合信息的度量方式称之为 香农熵。


熵是信息论中的概念,用来表示集合的无序程度,熵越大表示集合越混乱,反之则表示集合越有序。熵的计算公式为:

机器学习实战 决策树机器学习实战 决策树
其中,p(xi)是选择分类的概率。为了计算熵,我们需要计算所有类别的:
机器学习实战 决策树
其中,p(xi)表示在样本属于xi类的概率,-log2p(xi)表示样本属于xi类的信息量
当然,除了信息熵,还能用其他的来计算,比如信息增益比,基尼指数等等,都是基于信息增益的角度出发的,以减少集合混乱程度为目的。

代码如下:
#coding=utf-8
from math import log
import operator

def createDataSet():
    dataSet =[[1,1,'yes'],
              [1,1,'yes'],
              [1,0,'no'],
              [0,1,'no'],
              [0,1,'no']]  #创建数据集
    labels = ['no surfacing','flippers'] #分类属性
    return dataSet,labels

def calcShannonEnt(dataSet):   #计算给定数据集的香农熵
    numEntries = len(dataSet)  #求长度
    labelCounts = {}
    for featVec in 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)   #以2为底求对数
    return shannonEnt

def splitDataSet(dataSet,axis,value):  #划分数据集,三个参数为带划分的数据集,划分数据集的特征,特征的返回值
    retDataSet = []
    for featVec in dataSet:
        if featVec[axis] ==value:
            #将相同数据集特征的抽取出来
            reducedFeatVec = featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet #返回一个列表
'''
 
def chooseBestFeatureToSplit(dataSet):  #选择最好的数据集划分方式
    numFeature = len(dataSet[0])-1
    baseEntropy = calcShannonEnt(dataSet)
    bestInfoGain = 0.0
    beatFeature = -1
    for i in range(numFeature):
        featureList = [example[i] for example in dataSet] #获取第i个特征所有的可能取值
        uniqueVals = set(featureList)  #从列表中创建集合,得到不重复的所有可能取值
        newEntropy = 0.0
        for value in uniqueVals:
            subDataSet = splitDataSet(dataSet,i,value)  #以i为数据集特征,value为返回值,划分数据集
            prob = len(subDataSet)/float(len(dataSet))   #数据集特征为i的所占的比例
            newEntropy +=prob * calcShannonEnt(subDataSet)   #计算每种数据集的信息熵
        infoGain = baseEntropy- newEntropy
        #计算最好的信息增益,增益越大说明所占决策权越大
        if (infoGain > bestInfoGain):
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature
'''

def majorityCnt(classList):      #递归构建决策树
    classCount = {}
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote]=0
        classCount[vote]+=1
    sortedClassCount = sorted(classCount.iteritems(),key =operator.itemgetter(1),reverse=True)#排序,True升序
    return sortedClassCount[0][0] #返回出现次数最多的

def createTree(dataSet,labels):     #创建树的函数代码
    classList = [example[-1]  for example in dataSet]
    if classList.count(classList[0])==len(classList): #类别完全相同则停止划分
        return classList[0]
    if len(dataSet[0]) ==1:            #遍历完所有特征值时返回出现次数最多的
        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[:]
        #递归调用创建决策树函数
        myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
    return myTree  


未完待续!