基于决策树模式识别系统的设计与实现

基于决策树模式识别系统的设计与实现

1.1 题目的主要研究内容

工作的主要描述: 通过一个经典的打网球的例子,建立一个决策树分类模型,需要我们对文本数据进行分类处理,并对其特征提取。

1.2 题目研究的工作基础或实验条件

(1)硬件环境(Win10操作系统)

(2)软件环境(python语言)

1.3 数据集描述

是否去打网球(play)主要由天气(outlook)、温度(temperature)、湿度(humidity)、是否有风(windy)来确定。样本中共14条数据

1.4 特征提取过程描述

用熵来表示信息的复杂度,熵越大,则信息越复杂。公式如下:

在得到熵值之后,进一步计算数据信息增益,表示为两个信息熵的差值,信息增益越大,区分样本的能力越强。

通过天气情况看能否出行打网球,判断天气是晴、阴、空气湿度、温度、气温等状况来决定是否出行,首先,判断天气是否下雨,若是下雨,则取消出行,天气晴朗没有雨,则进行下一次判断,再通过判断天气的温度,若温度过高,就取消出行,气温适合则进行下一次判断,再进行湿度的判断。

1.5 主要程序代码(要求必须有注释)

import operator

from math import log

from operator import *

"""

这个算法是迭代好几次最后求出这个决策树,那么在下面分析的过程中,只分析第一次迭代的情况

"""

def storeTree(inputTree, filename):

    import pickle

    fw = open(filename, 'wb')  # pickle默认方式是二进制,需要制定'wb'

    pickle.dump(inputTree, fw)

    fw.close()

def grabTree(filename):

    import pickle

    fr = open(filename, 'rb')  # 需要制定'rb',以byte形式读取

    return pickle.load(fr)

def createDataSet():

    '''

    dataSet=[[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no']]

    labels = ['no surfacing','flippers']

    '''

    dataSet = [['sunny', 'hot', 'high', 'False', 'no'],

               ['sunny', 'hot', 'high', 'True', 'no'],

               ['overcast', 'hot', 'high', 'False', 'yes'],

               ['rain', 'mild', 'high', 'False', 'yes'],

               ['rain', 'cool', 'normal', 'False', 'yes'],

               ['rain', 'cool', 'normal', 'True', 'no'],

               ['overcast', 'cool', 'normal', 'True', 'yes'],

               ['sunny', 'mild', 'high', 'False', 'no'],

               ['sunny', 'cool', 'normal', 'False', 'yes'],

               ['rain', 'mild', 'normal', 'False', 'yes'],

               ['sunny', 'mild', 'normal', 'True', 'yes'],

               ['overcast', 'mild', 'high', 'True', 'yes'],

               ['overcast', 'hot', 'normal', 'False', 'yes'],

               ['rain', 'mild', 'high', 'True', 'no']]

    labels = ['outlook', 'temperature', 'humidity', 'windy']

    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)

    return shannonEnt

# 定义按照某个特征进行划分的函数splitDataSet

# 输入三个变量(待划分的数据集,特征,分类值)

# axis特征值中0代表no surfacing,1代表flippers

# value分类值中0代表否,1代表是

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)

    """

    返回出自身的value外的其他特征的全部情况,比如说如果是第一次迭代时,然后传递进来的参数是整个dataSet,那么axis是0,value是sunny

    那么就会得到value是sunny的全部的情况,并且把这个元组保存下来,但是不包括sunny

    就是下面这张结果:

    [['hot', 'high', 'False', 'no'], ['hot', 'high', 'True', 'no'], ['mild', 'high', 'False', 'no'], ['cool', 'normal', 'False', 'yes'], ['mild', 'normal', 'True', 'yes']]

    """

    return retDataSet  # 返回不含划分特征的子集

def chooseBestFeatureToSplit(dataSet):

    numFeature = len(dataSet[0]) - 1

    """

    在这里要说明一下,因为dataSet[0]是指每次迭代后的数据集,第一次时dataSet[0]值是:

    ['sunny', 'hot', 'high', 'False', 'no']

    那么,numFeature的值应该是4

    """

    baseEntropy = calcShannonEnt(dataSet)

    bestInforGain = 0

    bestFeature = -1

    for i in range(numFeature):

        """

        如果第一次numFeature=4,那么range(4)=[0,1,2,3],因此实际上就是依次统计列的值,然后存入featList中

        """

        featList = [number[i] for number in dataSet]  # 得到某个特征下所有值(某列)

        uniquelVals = set(featList)  # set无重复的属性特征值,得到所有无重复的属性取值

        """

        那么第一次迭代时,uniquelVals的值是:

        {'overcast', 'rain', 'sunny'} 对应第0列的无重复的值

        {'cool', 'mild', 'hot'}  对应第1列的无重复的值

        {'high', 'normal'}   对应第2列的无重复的值

        {'False', 'True'}   对应第3列的无重复的值

        """

        # 计算每个属性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  # 返回最大信息增益属性下标

# 递归创建树,用于找出出现次数最多的分类名称

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), reversed=True)  # reversed=True表示由大到小排序

    # 对字典里的元素按照value值由大到小排序

    return sortedClassCount[0][0]

def createTree(dataSet, labels):

    classList = [example[-1] for example in dataSet]  # 创建数组存放所有标签值,取dataSet里最后一列(结果)

    """

    第一次迭代时,这个classList应该是个列表,那么具体的值应该是下面显示的

    ['no', 'no', 'yes', 'yes', 'yes', 'no', 'yes', 'no', 'yes', 'yes', 'yes', 'yes', 'yes', 'no']

    """

    # 类别相同,停止划分

    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)

    print(uniqueVals)

    for value in uniqueVals:

        subLables = labels[:]  # 子集合 ,将labels赋给sublabels,此时的labels已经删掉了用于分类的特征的标签

        # 构建数据的子集合,并进行递归

        myTree[bestFeatLable][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLables)

    return myTree

if __name__ == "__main__":

    my_Data, labels = createDataSet()

    # print(calcShannonEnt(my_Data))

    Mytree = createTree(my_Data, labels)

    print(Mytree)

1.6 运行结果及分析

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李逍遥敲代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值