为了账号安全,请及时绑定邮箱和手机立即绑定

15.蜜汁代码(8)__终章

标签:
机器学习
#1.构造决策树
#计算给定数据集的熵
#导入log运算符
from math import log

def calEnt(dataSet):
    #获取数据集的行数
    numEntries=len(dataSet)
    #设置字典的数据结构
    labelCounts={}
    #提取数据集的每一行的特征向量
    for featVec in dataSet:
        #获取特征向量的最后一列的标签
        currentLabel=featVec[-1]
        #检测字典的关键字key中是否存在该标签
        #如果不存在keys()关键字
        if currentLabel not in labelCounts.keys():
            #将当前标签/0键值对存入字典中
            labelCounts[currentLabel]=0
        #否则将当前标签对应的键值加1
        #此处是为了统计标签的数量
        labelCounts[currentLabel]+=1
    #初始化熵为0
    Ent=0.0
    #对于数据集中所有的分类类别
    for key in labelCounts:
        #计算各个类别出现的频率
        prob=float(labelCounts[key])/numEntries
        #计算各个类别信息期望值
        Ent-=prob*log(prob,2)
    #返回熵
    return Ent


#2.构建决策树的数据集
#创建一个简单的数据集
#数据集中包含两个特征'no surfacing','flippers';
#数据的类标签有两个'yes','no'
def creatDataSet():
    dataSet=[[1,1,'yes'],
            [1,1,'yes'],
            [1,0,'no'],
            [0,1,'no'],
            [0,1,'no']]
    labels=['no surfacing','flippers']
    #返回数据集和类标签
    return dataSet,labels


#3.通过信息增益公式得到划分数据集的特征,划分数据集
#划分数据集:按照最优特征划分数据集
#dataSet:待划分的数据集
#axis:划分数据集的特征
#value:特征的取值
def splitDataSet(dataSet,axis,value):
    #需要说明的是,python语言传递参数列表时,传递的是列表的引用
    #如果在函数内部对列表对象进行修改,将会导致列表发生变化,
    #为了不修改原始数据集,创建一个新的列表对象进行操作
    reducedFeatVec = []
    #出问题时可以注释掉
    retDataSet=[]
    #提取数据集的每一行的特征向量
    for featVec in dataSet:
        #针对axis特征不同的取值,将数据集划分为不同的分支
        #如果该特征的取值为value
        if featVec[axis]==value:
            #将特征向量的0~axis-1列存入列表reducedFeatVec
            reducedFeatVec=featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet

#3.选择最好的划分数据集的特征
#使用某一特征划分数据集,信息增益最大,则选择该特征作为最优特征
def chooseBestFeatureToSplit(dataSet):
    #获取数据集特征的数目(不包含最后一列的类标签)
    numFeatures=len(dataSet[0])-1
    #计算未进行划分的信息熵
    baseEntropy=calEnt(dataSet)
    #最优信息增益    
    bestInfoGain=0.0
    #最优特征
    bestFeature=-1
    #利用每一个特征分别对数据集进行划分,计算信息增益
    for i in range(numFeatures):
        #得到特征i的特征值列表
        featList=[example[i] for example in dataSet]
        #利用set集合的性质--元素的唯一性,得到特征i的取值
        uniqueVals=set(featList)
        #信息增益0.0
        newEntropy=0.0
        #对特征的每一个取值,分别构建相应的分支
        for value in uniqueVals:
            #根据特征i的取值将数据集进行划分为不同的子集
            #利用splitDataSet()获取特征取值Value分支包含的数据集
            subDataSet=splitDataSet(dataSet,i,value)
            #计算特征取值value对应子集占数据集的比例
            prob=len(subDataSet)/float(len(dataSet))
            #计算占比*当前子集的信息熵,并进行累加得到总的信息熵
            newEntropy+=prob*calEnt(subDataSet)
        #计算按此特征划分数据集的信息增益
        #公式特征A,数据集D
        #则H(D,A)=H(D)-H(D/A)
        infoGain=baseEntropy-newEntropy
        #比较此增益与当前保存的最大的信息增益
        if (infoGain>bestInfoGain):
            #保存信息增益的最大值
            bestInfoGain=infoGain
            #相应地保存得到此最大增益的特征i
            bestFeature=i
        #返回最优特征
    return bestFeature

#4.定义一个多数表决函数majorityCnt()
#当遍历完所有的特征属性后,类标签仍然不唯一(分支下仍有不同分类的实例)
#采用多数表决的方法完成分类
def majorityCnt(classList):
    #创建一个类标签的字典
    classCount={}
    #遍历类标签列表中每一个元素
    for vote in classList:
        #如果元素不在字典中
        if vote not in classCount.keys():
            #在字典中添加新的键值对
            classCount[vote]=0
        #否则,当前键对应的值加1
        classCount[vote]+=1
    #对字典中的键对应的值所在的列,按照从大到小进行排序
    #classCount.items 列表对象
    #key=operator.itemgetter(1) 获取列表对象的第一个域的值
    #reverse=true 降序排序,默认是升序排序
    sortedClassCount=sorted(classCount.items,key=operator.itemgetter(1),reverse=true)
    #返回出现次数最多的类标签
    return sortedClassCount[0][0]



#5.通过递归的方式构建决策树
def createTree(dataSet,labels):
    #获取数据集中的最后一列的类标签,存入classList列表
    classList=[example[-1] for example in dataSet]
    #通过count()函数获取类标签列表中第一个类标签的数目
    #判断数目是否等于列表长度,相同表面所有类标签相同,属于同一类
    if classList.count(classList[0])==len(classList):
        return classList[0]
    #遍历完所有的特征属性,此时数据集的列为1,即只有类标签列
    if len(dataSet[0])==1:
        #多数表决原则,确定类标签
        return majorityCnt(classList)
    #确定出当前最优的分类特征
    bestFeat=chooseBestFeatureToSplit(dataSet)
    #在特征标签列表中获取该特征对应的值
    bestFeatLabel=labels[bestFeat]
    #采用字典嵌套字典的方式,存储分类树信息
    myTree={bestFeatLabel:{}}
    

    
    #复制当前特征标签列表,防止改变原始列表的内容
    subLabels=labels[:]
    #删除属性列表中当前分类数据集特征
    del(subLabels[bestFeat])
    #获取数据集中最优特征所在列
    featValues=[example[bestFeat] for example in dataSet]
    #采用set集合性质,获取特征的所有的唯一取值
    uniqueVals=set(featValues)
    #遍历每一个特征取值
    for value in uniqueVals:
        #采用递归的方法利用该特征对数据集进行分类
        #bestFeatLabel 分类特征的特征标签值
        #dataSet 要分类的数据集
        #bestFeat 分类特征的标称值
        #value 标称型特征的取值
        #subLabels 去除分类特征后的子特征标签列表
        myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
    return myTree


#------------------------测试算法1.------------------------------ 
"""
def main():
    myDat,labels  = creatDataSet()
    myTree = createTree(myDat,labels)
    print (myTree)

if __name__  == "__main__":
    main()
"""

#------------------------测试算法2.------------------------------    
#intputTree 构建好的决策树
#featLabels 特征标签列表
#testVec 测试实例

def classifier(inputTree,featLabels,testVec):
    #找到树的第一个分类特征,或者说根节点'no surfacing'
    #注意python2.x和3.x区别,2.x可写成firstStr=inputTree.keys()[0]
    #而不支持3.x
    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=classifier(secondDict[key],featLabels,testVec)
            #如果是叶子节点,则返回节点取值
            else: classLabel=secondDict[key]
    return classLabel
def main():
    myDat,labels = creatDataSet()
    myTree = createTree(myDat,labels)
    print ('[1,0] :',classifier(myTree,labels,[1,0]))
    print ('[1,1] :',classifier(myTree,labels,[1,1]))

if __name__  == "__main__":
    main()

测试1

测试2

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消