使用决策树预测隐形眼镜类型

1、算法思想:从根节点开始,对实例的某一特征进行测试,根据测试结果将实例分配到其子节点;每一个子节点对应着该特征的一个取值。如此递归地对实例进行测试并分配,直至达到叶节点。最后将实例分配到叶节点的类中。

    k近邻算法可以完成多分类任务,缺点是无法给出数据的内在含义,决策树的主要优势在于数据形式容易理解

 2、伪代码:

      思路是:如果某个分支下的数据属于同一类型,则无需分割 返回类标签;如果数据子集的数据不属于同一类型,则需要重复划分数据子集,直到相同类型的数据在同一个数据子集内。

3、度量数据集的无须程度

    划分数据集的原则是将无序的数据变得有序,集合信息的度量方式称为香农熵

  

   熵越高 混合的数据越多,得到熵之后就可以按照最大信息增益的方法划分数据集

   测量信息熵-划分的数据集-度量划分数据集的熵

   代码如下:

# -*- 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:  #the the number of unique elements and their occurance
        currentLabel = featVec[-1]
        if currentLabel not in labelCounts.keys(): 
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1
    shannonEnt = 0.0
    for key in labelCounts:
        #字典的运用,dict[key]=value
        prob = float(labelCounts[key])/numEntries
        shannonEnt -= prob * log(prob,2)   #log base 2
    return shannonEnt
#划分数据集
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)  
            #append() 向列表尾部追加一个新元素,列表只占一个索引位,在原有列表上增加,如果处理对象是列表 则将整个列表作为一个元素添加
            #extend() 向列表尾部追加一个列表,将列表中的每个元素都追加进来,在原有列表上增加
    return retDataSet
#选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0])-1   #特征的个数
    bestEntroy = calcShannonEnt(dataSet)   #entroy熵,初始值设为数据集的熵
    bestInfoGain = 0.0   #信息增益初始值
    bestFeature = -1
    for i in range(numFeatures):
        featureList = [example[i] for example in dataSet] #第i个特征所有的取值
        uniqueVals = set(featureList)  #去重,set表示集合 集合的特点是每个值互不相同 从列表中创建集合可以得到列表中的唯一元素值
        newEntropy = 0.0
        for value in uniqueVals: #对每一种唯一属性划分数据集
            subDataSet = splitDataSet(dataSet,i,value)   
            prob = len(subDataSet)/float(len(subDataSet))
            newEntropy += prob * calcShannonEnt(subDataSet)  ##每种划分方式经验条件熵的和
        infoGain = bestEntroy - 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.items(),key = operator.itemgetter(1),reverse = True )
    return sortedClassCount[0][0]
#创建树函数代码
def createTree(dataSet,labels):
    #将dataSet中最后一列的元素(也就是类标签)放入到classList列表中
    classList = [example[-1] for example in dataSet]
    # count()方法用于统计字符串里某个字符出现的次数  
    #若相等表示List中的标签属于同一列别
    if classList.count(classList[0]) == len(classList):
        return classList[0]
    # len()方法返回字符串长度或者列表元素个数
    #表示只有类别列,没有属性列
    if len(dataSet[0])==1:
        #多数表决原则 返回出现次数最多的列别
        return mahorityCnt(classList) 
    #确定当前最优的分类特征
    bestFeat = chooseBestFeatureToSplit(dataSet)
    #在特征标签列表中获取该特征对应的值
    bestFeatLabel = labels[bestFeat]
    #按照字典嵌套字典的方式 存储分类树信息
    myTree = {bestFeatLabel:{}}
    del(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
#--------------以上完成了决策树的构建----------------
#--------------以下的是使用决策树分类----------------  
#完成决策树的构造后,采用决策树实现具体应用
def classify(inputTree,featLabels,testVec):
    #找到树的第一个分类特征,或者说根节点'no surfacing'
    #注意python2和3区别,2可写成firstStr=inputTree.keys()[0] 而不支持3
    firstStr=list(inputTree.keys())[0]
    #从树中得到该分类特征的分支,有0和1
    secondDict=inputTree[firstStr]
    #根据分类特征的索引找到对应的标称型数据值
    #'no surfacing'对应的索引为0
    featIndex=featLabels.index(firstStr)
    #遍历分类特征所有的取值
    for key in secondDict.keys():
        #测试实例的第0个特征取值等于第key个子节点
        if testVec[featIndex]==key:
            #type()函数判断该子节点是否为字典类型
            if type(secondDict[key]).__name__=='dict':
                #子节点为字典类型,则从该分支树开始继续遍历分类
                classLabel=classify(secondDict[key],featLabels,testVec)
            #如果是叶子节点,则返回节点取值
            else: 
                classLabel=secondDict[key]
    return classLabel
#--------------决策树的存储----------------
#构造决策树好费时间,因此可以将构造好的决策树存储起来下次直接用
#决策树的存储:python的pickle模块序列化决策树对象,使决策树保存在磁盘中
def storeTree(inputTree,filename):
    #导入pickle模块
    import pickle
    #创建一个可以'写'的文本文件
    #pickle存储方式默认是二进制方式
    #这里,如果按树中写的'w',将会报错write() argument must be str,not bytes
    #所以这里改为二进制写入'wb'
    fw=open(filename,'wb')
    #pickle的dump函数将决策树写入文件中
    pickle.dump(inputTree,fw)
    #写完成后关闭文件
    fw.close()
#取决策树操作    
def grabTree(filename):
    import pickle
    #对应于二进制方式写入数据,'rb'采用二进制形式读出数据
    fr=open(filename,'rb')
    return pickle.load(fr)
#--------------示例:使用决策树预测隐形眼镜类型----------------
def predictLensesType(filename):
    #打开文本数据
    fr=open(filename)
    #将文本数据的每一个数据行按照tab键分割,并依次存入lenses
    lenses=[inst.strip().split('\t') for inst in fr.readlines()]
    #创建并存入特征标签列表
    lensesLabels=['age','prescript','astigmatic','tearRate']
    #根据继续文件得到的数据集和特征标签列表创建决策树
    lensesTree=createTree(lenses,lensesLabels)
    return lensesTree

def test():
    myData, labels = createDataSet()
    myTree = createTree(myData, labels)
    # 再创建一次数据的原因是创建决策树函数会将labels值改动
    myData, labels = createDataSet()
    print (classify(myTree, labels, [1,1]))


# 主方法
if __name__ == "__main__":
    myData,labels=tree.createDataSet()
    myTree=tree.createTree(myData,labels)
    print (myTree)

 

posted on 2018-04-19 15:24  Aaron12  阅读(968)  评论(0编辑  收藏  举报

导航