机器学习—决策树

决策树

注:此博客写于2019年LSGO实验室的机器学习算法培训中

决策树划分数据集的时候,总的原则是让数据变得更加有序,这里先介绍信息增益与熵的概念

信息增益:划分数据前后信息发生的变化叫做信息增益,划分数据时,我们会选择信息增益最大的特征对数据集进行划分

熵:
机器学习—决策树_第1张图片
采用递归的方法构造决策树:

from math import log
import operator
## 计算香农熵
def calcShannonEnt(dataSet):
    numEntries = len(dataSet)                       #计算数据集的行数
    labelCounts = {}                                #创建字典,键是类别,值是频数
    for featVec in dataSet:                         #遍历每一行数据
        currentLabel = featVec[-1]                   #取出每一行该行的最后一个数据,即类别
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel]=0              #该类别还未存入字典中。则先初始化为0
        labelCounts[currentLabel]+=1
    shannonEnt = 0.0                                 #初始化香农熵
    for key in labelCounts:
        prob = float(labelCounts[key]/numEntries)
        shannonEnt-=prob*log(prob,2)
    return shannonEnt
## 创建数据集
def creatDataSet():
    dataSet = [[1, 1, 'yes'],
               [1, 1, 'yes'],
               [1, 0, 'no'],
               [0, 1, 'no'],
               [0, 1, 'no']]
    labels = ['no surfacing', 'flippers', 'labels']  # 两个特征:'no surfacing','flippers';一个标签'labels'
    return dataSet
## 划分数据集
def splitDataSet(dataSet,axis,value):
    retDataSet = []
    for featvec in dataSet:
        if featvec[axis]==value:                       #判断是否满足索引条件
            reduced_featvec = featvec[:axis]           #将出索引值以外的数据项添加到retDataSet
            reduced_featvec.extend(featvec[axis+1:])
            retDataSet.append(reduced_featvec)
    return retDataSet
## 求最佳划分特征
def choose_beatfeature_tosplit(dataSet):
    numsfeature = len(dataSet[0])-1
    baseEntropy = calcShannonEnt(dataSet)              #原始香农熵
    bestInfoGain = 0.0                                 #初始化信息增益
    bestFeature = -1                                   #初始化最佳切分列
    for i in range(numsfeature):
        featList=[example[i] for example in dataSet]   #转化为列表,内容是该索引下的所有元素
        uniqueVals=set(featList)                        #得到所有可以用来分类的特征值
        #使用set函数去重
        newEntrpy = 0.0                                #初始化子节点的香农熵
        for value in uniqueVals:
            subdataSet = splitDataSet(dataSet,i,value)
            pro = len(subdataSet) / float(len(dataSet)) #求香农熵
            newEntrpy += pro * calcShannonEnt(subdataSet)
        infoGain = baseEntropy - newEntrpy
        if (infoGain) > bestInfoGain:                   #比较当前计算的信息增益与保存最大的信息增益
            bestInfoGain = infoGain                     #保存为最大信息增益
            bestFeature = i
    return bestFeature

## 在使用完所有的划分数据集的属性后,若类标签依然不是唯一的,则用多数表决原则来决定该子节点的类别
def majorityCnt(classList):
    classCount = {}
    for Catagory in classList:
        if Catagory not in classCount.key():
            classCount[Catagory]=0
        classCount[Catagory]+=1

##递归地创建决策树
def creatTree(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)
    bestfeature = choose_beatfeature_tosplit(dataSet)       #当前最优的划分特征
    bestfeaturelabel = labels[bestfeature]                  #在特征标签labels中获取对应的特征标签值
    myTree={bestfeaturelabel:{}}                            #用字典来嵌套的方式来存储树的信息
    del(labels[bestfeature])                                #删除当前特征
    featValues = [example[bestfeature] for example in dataSet]  #获取最佳划分特征的所在列
    uniqueVals = set(featValues)                            #去重
    for value in uniqueVals:
        sublabels = labels[:]                                #复制当前特征列,防止修改原列表的内容
        myTree[bestfeaturelabel][value]=creatTree(splitDataSet(dataSet,bestfeature,value),sublabels)
    return myTree




myData = creatDataSet()
print(myData)
labels = ['no surfacing', 'flippers', 'labels']
(creatTree(myData, labels))
# print(choose_beatfeature_tosplit(myData))
# print(splitDataSet(myData, 0,0))
# print(calcShannonEnt(myData))

你可能感兴趣的:(机器学习—决策树)