机器学习笔记(2)-决策树

来源:互联网 发布:手机淘宝积分在那里看 编辑:程序博客网 时间:2024/06/05 05:01

决策数简介

这里写图片描述
熵(entropy)指的是体系的混乱的程度。
信息熵(香农熵)是一种信息的度量方式,表示信息的混乱程度,也就是说:信息越有序,信息熵越低。
信息增益是指在划分数据集前后信息发生的变化。
构造决策树

检测数据集中的所有数据的分类标签是否相同:    If so return 类标签    Else:        寻找划分数据集的最好特征(划分之后信息熵最小,也就是信息增益最大的特征)        划分数据集        创建分支节点            for 每个划分的子集                调用函数 createBranch (创建分支的函数)并增加返回结果到分支节点中        return 分支节点

ID3算法实现

数据处理
这里写图片描述

def createDataSet():    dataSet = [[1, 1, 'yes'],[1, 1, 'yes'],[1, 0, 'no'],[0, 1, 'no'],[0, 1, 'no']]    labels = ['no surfacing', 'flippers']    # labels  露出水面   脚蹼    return dataSet, labels

数据集香农熵
这里写图片描述

def calcShannonEnt(dataSet):    '''calcShannonEnt(calculate Shannon entropy 计算给定数据集的香农熵)    :param dataSet: dataSet 数据集    :return: 返回每一组feature下的某个分类下,香农熵的信息期望    '''    numEntries = len(dataSet)   # 求list的长度,表示计算参与训练的数据量    labelCounts = {}     # 计算分类标签label出现的次数    for featVec in dataSet:        currentLabel = featVec[-1]    # 将当前实例的标签存储,即每一行数据的最后一个数据代表的是标签        if currentLabel not in labelCounts.keys():   # 为所有可能的分类创建字典,如果当前的键值不存在,则扩展字典并将当前键值加入字典。每个键值都记录了当前类别出现的次数。            labelCounts[currentLabel] = 0        labelCounts[currentLabel] += 1    shannonEnt = 0.0    # 对于label标签的占比,求出label标签的香农熵    for key in labelCounts:        prob = float(labelCounts[key])/numEntries   # 使用所有类标签的发生频率计算类别出现的概率。        shannonEnt -= prob * log(prob, 2)  # 计算香农熵,以 2 为底求对数    return shannonEnt

给定特征划分数据集
splitDataSet(dataSet, 0, 1) –> [[1, ‘yes’],[1, ‘yes’],[0, ‘no’ ]]
这里写图片描述

def splitDataSet(dataSet, index, value):    '''通过遍历dataSet数据集,求出index对应的colnum列的值为value的行    :param dataSet: 待划分的数据集    :param index: 划分数据集的特征    :param value: 需要返回的特征的值    :return: retDataSet:index列为value的数据集【该数据集需要排除index列】    '''    retDataSet = []    for featVec in dataSet:        if featVec[index] == value:            reducedFeatVec = featVec[:index]            reducedFeatVec.extend(featVec[index+1:])            retDataSet.append(reducedFeatVec)    return retDataSet>>> result = []>>> result.extend([1,2,3])  # [1, 2, 3]>>> result.append([4,5,6])  # [1, 2, 3, [4, 5, 6]]>>> result.extend([7,8,9])  # [1, 2, 3, [4, 5, 6], 7, 8, 9]

选择最好的特征集划分方式

def chooseBestFeatureToSplit(dataSet):    '''选择最好的特征    :param dataSet: 数据集    :return: bestFeature:最优的特征列    '''    numFeatures = len(dataSet[0]) - 1    baseEntropy = calcShannonEnt(dataSet)   # label的信息熵    bestInfoGain, bestFeature = 0.0, -1   # 最优的信息增益值, 和最优的Featurn编号    for i in range(numFeatures):        featList = [example[i] for example in dataSet]        uniqueVals = set(featList)  # 获取剔重后的集合,使用set对list数据进行去重        newEntropy = 0.0  # 创建一个临时的信息熵        for value in uniqueVals:  # 遍历某一列的value集合,计算该列的信息熵             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                   

创建树

def majorityCnt(classList):    '''选择出现次数最多的一个结果    :param classList: label列的集合    :return: bestFeature:最优的特征列    '''    classCount = {}    for vote in classList:        if vote not in classCount.keys():            classCount[vote] = 0        classCount[vote] += 1    # 倒叙排列classCount得到一个字典集合,然后取出第一个就是结果(yes/no),即出现次数最多的结果    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)    return sortedClassCount[0][0]def createTree(dataSet, labels):    classList = [example[-1] for example in dataSet]    if classList.count(classList[0]) == len(classList):  # 第一个停止条件:所有的类标签完全相同,则直接返回该类标签。        return classList[0]    if len(dataSet[0]) == 1:  # 如果数据集只有1列,那么最初出现label次数最多的一类,作为结果        return majorityCnt(classList)    bestFeat = chooseBestFeatureToSplit(dataSet)  # 选择最优的列,得到最优列对应的label含义    bestFeatLabel = labels[bestFeat]  # 获取label的名称    myTree = {bestFeatLabel: {}}    del(labels[bestFeat])    featValues = [example[bestFeat] for example in dataSet]    uniqueVals = set(featValues)    for value in uniqueVals:        subLabels = labels[:]   # 求出剩余的标签label        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)  # 遍历当前选择特征包含的所有属性值,在每个数据集划分上递归调用函数createTree()    return myTree