机器学习实战笔记---决策树--如何构建决策树

 本文转自Jack Cui http://cuijiahua.com/blog/2017/11/ml_3_decision_tree_2.html#

ID3算法

核心就是在决策树各个结点上对应信息增益准则选择特征,递归的构造决策树。具体方法是:从根结点开始,对结点计算所有可能的特征信息增益,选择信息增益最大的特征作为结点特征,由该特征的不同取值建立子节点;再对子节点递归地调用以上方法,构建决策树;直到所有特征的信息增益均很小或没有特征可以选择为止。最后得到一个决策树。

import operator

#计算数据集的香农熵
def calcShannonEnt(dataset):
    numEntries=len(dataset)#求数据集列表的行数
    labelCounts={}
    for featVec in dataset:
        currentLabel=featVec[-1]
        #如果该键不在字典中,则向字典中添加该键并赋值为0
        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=[[0, 0, 0, 0, 'no'],                       
             [0, 0, 0, 1, 'no'],
             [0, 1, 0, 1, 'yes'],
             [0, 1, 1, 0, 'yes'],
             [0, 0, 0, 0, 'no'],
             [1, 0, 0, 0, 'no'],
             [1, 0, 0, 1, 'no'],
             [1, 1, 1, 1, 'yes'],
             [1, 0, 1, 2, 'yes'],
             [1, 0, 1, 2, 'yes'],
             [2, 0, 1, 2, 'yes'],
             [2, 0, 1, 1, 'yes'],
             [2, 1, 0, 1, 'yes'],
             [2, 1, 0, 2, 'yes'],
             [2, 0, 0, 0, 'no']]
    labels=["年龄","有工作","有自己的房子","信贷情况"]
    return dataSet,labels    

#按照给定的特征划分数据集  
def splitDataSet(dataSet,axis,value):
    retDataSet=[]
    for featVec in dataSet:
       if featVec[axis]==value:
           reducedFeatVec=featVec[:axis]
           #注意extend和append的区别
           reducedFeatVec.extend(featVec[axis+1:])#[]
           retDataSet.append(reducedFeatVec)#[[]]          
    return retDataSet    

#选择最优特征
def chooseBestFeatureToSplit(dataSet):
    numFeatures=len(dataSet[0])-1
    bestInfoGain=0.0
    bestFeature=-1
    for i in range(numFeatures):
        #当i=0时,[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2]
        featList=[example[i] for example in dataSet]
        uniqueVals=set(featList)#元素不可重复
        newEntropy=0.0
        for value in uniqueVals:
            subDataSet=splitDataSet(dataSet,i,value)
            prob=len(subDataSet)/float(len(dataSet))
            newEntropy+=prob*calcShannonEnt(subDataSet)
        infoGain=shannon-newEntropy
        if(infoGain>bestInfoGain):
            bestInfoGain=infoGain
            bestFeature=i
    return bestFeature    
    
#统计classList中出现次数最多的元素
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,featLabels):
    classList=[example[-1] for example in dataSet]
    if classList.count(classList[0])==len(classList):
        return classList[0]
    
    #遍历完所有特征时返回出现次数最多的类标签
    #它的作用是使用完了所有特征,仍然不能将数据集划分成仅包含唯一类别的分组。
    #此时使用majorityCnt函数挑选出现次数多的类别作为返回值。 
    #如果没有调用它,则因为这个训练集可以直接划分成仅包含唯一类别的分组,所以不会触发这个终止条件。
    if len(dataSet[0])==1:
        return majorityCnt(classList)
    bestFeat=chooseBestFeatureToSplit(dataSet)
    bestFeatLabel=labels[bestFeat]
    featLabels.append(bestFeatLabel)
    myTree={bestFeatLabel:{}}
    del(labels[bestFeat])#删除已经使用过的特征标签
    featValues=[example[bestFeat] for example in dataSet]#得到训练集中最优特征的属性值
    uniqueVals=set(featValues)#去重
    for value in uniqueVals:
       myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),labels,featLabels)
    return myTree
  
dataSet,labels=createDataSet()
shannon=calcShannonEnt(dataSet)    
featLabels=[]
myTree=createTree(dataSet,labels,featLabels)
print(myTree)    

用决策树分类:比较测试数据与决策树上的数值,递归执行该过程直到进入叶子结点;最后将测试数据定义为叶子结点所属的类型

#决策树分类
def classify(inputTree,featLabels,testVec):
    firstStr=next(iter(inputTree))#有自己的房子,有工作
    secondDict=inputTree[firstStr]
    featIndex=featLabels.index(firstStr)
    print("featIndex:",featIndex)
    for key in secondDict.keys():
        if testVec[featIndex]==key:
            if type(secondDict[key]).__name__=='dict':
                classLabel=classify(secondDict[key],featLabels,testVec)
            else:
                classLabel=secondDict[key]
    return classLabel
    
   
  
dataSet,labels=createDataSet()
shannon=calcShannonEnt(dataSet)    
featLabels=[]
myTree=createTree(dataSet,labels,featLabels)
print(myTree)    
testVec=[0,1]
result=classify(myTree,featLabels,testVec)
if result=='yes':
    print("放贷")
if result=='no':
    print("不放贷")

 

猜你喜欢

转载自blog.csdn.net/sinat_38998284/article/details/81699057