欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-02-03 18:21:34
...

决策数简介

机器学习笔记(2)-决策树
熵(entropy)指的是体系的混乱的程度,是表示随机变量X不确定性的度量。设X是一个取有限个值的离散随机变量,其概率分布为:
机器学习笔记(2)-决策树
则随机变量X的熵定义为:
机器学习笔记(2)-决策树
性质:熵只依赖X的分布,与X的取值无关;熵的范围0≤H(X)≤logn,n为X取值数目;概率分布越均匀,熵取值越大,随机变量不确定性越大。上面公式中的对数以2为底或以e为底,这时熵的单位分别称为比特(bit)或纳特(nat)。
条件熵条件熵H(Y|X)表示在已知随机变量X的条件下随机变量Y的不确定性。用于特征选择时,该值越小即不确定性越小,其对应的特征越好。
H(Y|X=xi)为X给定条件下X=xi时,Y的条件概率分布的熵。 H(Y|X)实质为H(Y|X=xi)的数学期望。条件熵计算公式:
机器学习笔记(2)-决策树
信息熵(香农熵)是一种信息的度量方式,表示信息的混乱程度,也就是说:信息越有序,信息熵越低。P(x)是变量出现的概率;信息熵越大,变量中包含的信息量就越大。同时,也说明了变量的不确定性也越大。
机器学习笔记(2)-决策树
信息增益是指在划分数据集前后信息发生的变化。
机器学习笔记(2)-决策树
信息增益比信息增益的局限性是偏向于选择取值较多的特征,信息增益可以校正这个问题。 特征A对训练数据集D的信息增益比gR(D,A)定义为其信息增益g(D,A)与训练数据集D关于特征A的值的熵HA(D)之比,即:
机器学习笔记(2)-决策树
机器学习笔记(2)-决策树

决策树生成

构造决策树

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

ID3算法实现

ID3算法使用信息增益作为特征选择的度量。
结束条件:D中所有实例都属于同一类;信息增益值小于特定的阈值;没有其他特征可以选择了。
构建树的过程中对于选中的某一个特征,其有多少种取值,就分出多少条边。
下层的节点在进行特征选择的时候不会再用到上层用过的特征。
数据处理
机器学习笔记(2)-决策树

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

数据集香农熵
机器学习笔记(2)-决策树

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’ ]]
机器学习笔记(2)-决策树

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 

C4.5算法

C4.5 对ID3的改进,除了特征选择度量以外,另外两点是可以处理连续值型属性以及处理缺失值。
a,处理连续值型属性
机器学习笔记(2)-决策树
b,处理缺失值
机器学习笔记(2)-决策树