《机器学习实战》读书笔记 第三章 决策树(part 3)

#以下为ID3算法个征独家解(tu)说(cao)版本。
from math import log
import operator

#1.构建样本数据集,前两个维度是特征维度(对应于labels里的特征名),最后一个维度是类别维度(鱼类、非鱼类)
def createDataSet():
    dataSet = [[1, 1,'yes'],
               [1, 1,'yes'],
               [1, 0,'no'],
               [0, 1,'no'],
               [0, 1,'no']]
    labels = ['nosurfacing','flippers']
    return dataSet,labels


#2.计算样本数据集的熵。注意:只计算类别维度!
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


#3.划分样本数据集。注意凡需复制链表时,一定要使用[:]截取,否则后续操作可能会改变原始链表的值 
#每次进行划分时,选取的特征维度(axis)会被损失            
def splitDataSet(dataSet, axis, value):
    retDataSet = []
    for featVec indataSet:
       if featVec[axis] == value:
          reducedFeatVec = featVec[:axis]  
          reducedFeatVec.extend(featVec[axis+1:])
          retDataSet.append(reducedFeatVec)
    return retDataSet


#4. 选取使得 信息增益最大的特征进行分类 #分类后熵的计算:以小数据集占大数据集的比例为权重,加权求和
def chooseBestFeatureToSplit(dataSet):
    numFeatures =len(dataSet[0]) - 1    
    baseEntropy =calcShannonEnt(dataSet)
    bestInfoGain = 0.0;bestFeature = -1
    for i in range(numFeatures):        #选一个特征进行分类 
       featList = [example[i] for example in dataSet]         #链表推导:复制数据集第i列
       uniqueVals = set(featList)          #set()返回链表元素的集合
       newEntropy = 0.0
       for value in uniqueVals:             #计算划分后的熵
           subDataSet= splitDataSet(dataSet, i, value)
           prob =len(subDataSet)/float(len(dataSet))
           newEntropy+= prob * calcShannonEnt(subDataSet)    
       infoGain = baseEntropy - newEntropy              #计算信息增益
       if (infoGain > bestInfoGain):    
          bestInfoGain = infoGain      
          bestFeature = i                #如果信息增益最大,这个特征就是被选中的特征
    return bestFeature

               
#5.投票表决函数
#递归终止条件(样本集不可再分)有两种情况:
#1)样本集中所有实例类别都相同(虽然特征可能不同)
#2) 样本集中所有特征都损失掉了(虽然类别可能不同)
#1)好说,直接用那个类别作为叶子结点;2)的话,执行多数暴政法则,用出现最多的类别作为叶子结点
def majorityCnt(classList):           #这个投票函数和第二章的那个本质是一样的,虽然写法稍有不同
    classCount={}
    for vote in classList:
       if vote not in classCount.keys():classCount[vote]=0            
       classCount[vote] += 1
    sortedClassCount =sorted(classCount.iteritems(), key=operator.itemgetter(1),reverse=True)
    returnsortedClassCount[0][0]


#6.递归构建决策树
def createTree(dataSet,labels):
#####################################递归终止条件######################################
    classList = [example[-1]for example in dataSet]             #链表推导:复制数据集最后一列(类别列)
    ifclassList.count(classList[0]) == len(classList):             #终止条件1)
       return classList[0]
    if len(dataSet[0]) == 1:            #终止条件2)
       return majorityCnt(classList)               #叶子结点被谁承包?投票表决!
##############################终止条件完毕,以下进入正文#################################
    bestFeat =chooseBestFeatureToSplit(dataSet)          #选择划分特征(列索引)
    bestFeatLabel =labels[bestFeat]             #按照列索引找到对应特征的名字
    myTree ={bestFeatLabel:{}}              #第一次划分的特征作为根结点
   del(labels[bestFeat])             #删除该特征(接下来在splitDataSet()中对应的列也会被删除)
    featValues =[example[bestFeat] for example in dataSet]        
    uniqueVals =set(featValues)
    for value inuniqueVals:
       subLabels =labels[:]      #重申:复制链表时要使用[:]截取,否则后续操作可能会改变原始链表的值
       myTree[bestFeatLabel][value] =createTree(splitDataSet(dataSet, bestFeat,value),subLabels)           
 #递归开始,接下来就是见证奇迹的时刻(●'◡'●)ノ
    returnmyTree            #递归终止时,返回决策树  

                   
#7.使用决策树进行分类 
def classify(inputTree,featLabels,testVec):
    firstStr =inputTree.keys()[0]           #当前树的根结点
    secondDict =inputTree[firstStr]           #根结点的子树们
    featIndex =featLabels.index(firstStr)          #找到根结点特征的索引
    key = testVec[featIndex]              #根据索引找到测试样本对应于此特征的特征值
    valueOfFeat =secondDict[key]        #该特征值对应的子树,准备下一次分类
    ifisinstance(valueOfFeat, dict):          #如果子树是字典,说明还可以再分
       classLabel = classify(valueOfFeat, featLabels,testVec)          #递归调用分类器
    else: classLabel =valueOfFeat             #如果子树不是字典,说明已到达叶子结点
    return classLabel             #返回叶子结点的类别名


#8.存储决策树
def storeTree(inputTree,filename):
    import pickle
    fw = open(filename,'w')          #以写模式打开文件(文件原有内容会被覆盖)
    pickle.dump(inputTree,fw)           #把决策树放进去
    fw.close()          #把文件关上


#9.打开存储的决策树    
def grabTree(filename):
    import pickle
    fr =open(filename)
    return pickle.load(fr)


 
 
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值