【机器学习】决策树-01

心得体会:

  1决策树是在 香农熵 和 信息增益 的基础上构建的

  2筛选决策标签,当筛去该标签时得到香农熵最优结构时,选择该决策标签,不断筛选直到选完所有标签(或余下结果都一样)

  3取余下结果中最多的结果作为该叶节点的返回结果

  4数据结构是字典树

#3-1构造决策树

#计算香农熵
from math import log
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

#自定义数据
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

# myDat,labels=createDataSet()
# print(calcShannonEnt(myDat))

#按照给定特征划分数据集
def splitDataSet(dataSet,axis,value):#选择axis位是value的数据
    retDataSet=[]
    for featVec in dataSet:
        if featVec[axis]==value:#选择数据集中符合条件的数据
            reducedFeatVec=featVec[:axis]#axis之前的数据
            reducedFeatVec.extend(featVec[axis+1:])#axis之后的数据
            retDataSet.append(reducedFeatVec)#新数据集(已经筛选过axis位)
    return retDataSet

# myDat,labels=createDataSet()
# print(myDat)
# print(splitDataSet(myDat,0,1))
# print(splitDataSet(myDat,0,0))

# 选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
    numFeatures=len(dataSet[0])-1   #最后一个数据是结果
    baseEntropy=calcShannonEnt(dataSet) #计算基础香农熵
    bestInfoGain=0.0 #信息增益
    bestFeature=-1  #初始特征位是-1
    for i in range(numFeatures):
        featList=[example[i] for example in dataSet] # 复制dataset
        uniqueVals=set(featList) # 数据去重,得到i位置的域
        newEntropy=0.0  #i位置的总信息期望
        for value in uniqueVals:
            subDataSet=splitDataSet(dataSet,i,value)    #筛选i位置为value的数据
            prob=len(subDataSet)/float(len(dataSet))    #这些数据的占比
            newEntropy+=prob*calcShannonEnt(subDataSet) #筛选i位置为value的数据 的信息期望
        inoGain=baseEntropy-newEntropy #筛选i位置后剩下的信息期望
        if(inoGain>bestInfoGain):#选择筛去i后余下香农熵最小的,筛去i数据最整齐
            bestInfoGain=inoGain
            bestFeature=i
    return bestFeature

# myDat,labels=createDataSet()
# print(chooseBestFeatureToSplit(myDat))

#递归构建决策树
import operator
#返回出现次数最多的分类名称
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)#按字典(k,v)第一个域v排序
    return sortedClassCount[0][0]   #返回classList中val最大的key

#创建决策树
def createTree(dataSet,labels):#输入数据和位置含义
    classList=[example[-1] for example in dataSet] #返回所有结果
    if classList.count(classList[0])==len(classList):   #如果(第0位数据出现的次数和长度一样)剩下结果都一样
        return classList[0] #返回第0位的结果,因为都一样
    if len(dataSet[0])==1:  #如果数据只剩下最后一位(最后一位是结果 )
        return majorityCnt(classList)   #返回最多的结果
    bestFeat=chooseBestFeatureToSplit(dataSet)  #选择最优的位置
    bestFeatLabel=labels[bestFeat]  #最优位置的结果
    myTree={bestFeatLabel:{}} #字典树 bestFeatLabel:{}中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

# myDat,labels=createDataSet()
# mytree=createTree(myDat,labels)
# cur=mytree
# while True:
#     if(type(cur)==dict):
#         label=list(cur.keys())[0]   #因为字典树只有一个根节点
#         print("%s ?"%label)
#         key=int(input("input_1/0(yes/no):"))#key要强制转换成int不然默认是string
#         cur=cur[label][key] #选择分支
#     else:
#         print(cur)
#         break

 

posted @ 2020-07-08 17:45  海底淤泥  阅读(215)  评论(0编辑  收藏  举报