机器学习实战之决策树(基础)

信息:若Xi(i=1,2,...n)为分类类别,则信息值 \mathbf{i}(Xi) = -\log _{2}^{\mathbf{p}(Xi)}.(X为某一特征)

熵:(随机变量的不确定性的度量)信息的数学期望。E =  \sum_{i=1}^{n}\mathbf{p}(Xi)\cdot \mathbf{i}(Xi)

经验熵:概率由数学估计得到。

# -*- coding: UTF-8 -*-
from math import log
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 calcShannonEnt(dataSet):
    numEntires = len(dataSet)                        #返回数据集的行数
    labelCounts = {}                                #保存每个标签(Label)出现次数的字典
    for featVec in dataSet:                            #对每组特征向量进行统计
        currentLabel = featVec[-1]                    #提取标签(Label)信息
        labelCounts[currentLabel] = labelCounts.get(currentLabel,0)+1 #Label计数,如果标签(Label)没有放入统计次数的字典,添加进去
             
    shannonEnt = 0.0                                #经验熵(香农熵)
    for key in labelCounts:                            #计算香农熵
        prob = float(labelCounts[key]) / numEntires    #选择该标签(Label)的概率
        shannonEnt -= prob * log(prob, 2)            #利用公式计算
    return shannonEnt                           #返回经验熵(香农熵)

if __name__ == '__main__':
    dataSet, features = createDataSet()
    print(dataSet)
    print(calcShannonEnt(dataSet))

 条件熵H(Y|X):表示在已知随机变量X的条件下随机变量Y的不确定性。随机变量X给定的条件下随机变量Y的条件熵(conditional entropy) 定义为X给定条件下,Y的条件概率分布的熵(H(Y|Xi))对X的数学期望:

                                         H(Y|X) = \sum_{i=1}^{n}\mathbf{pi}\cdot \mathbf{H}(Y|Xi) ,  其中pi=p(X=Xi), i=1,2,3...n。

 

信息增益(互信息):相对于某个特征而言。决策树学习中的信息增益等价于训练数据集中类(标签)与特征的互信息。因此特征A对训练数据集D的信息增益g(D,A),定义为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差,即                                                        \mathbf{g}(D,A) = H(D) - H(D|A) =  H(D)-\sum_{i=1}^{n}\mathbf{pi}\cdot \mathbf{H}(Y|Ai)

 

以代码中数据为例,A可以是年龄,则Ai可取青年(i=1),中年(i=2),老年(i=3)。H(D)即为标签类别(Yes/No)的熵,H(D|A1)即为青年样本对分类标签的熵,p1=青年样本数/样本总数。 

# -*- coding: UTF-8 -*-
from math import log

"""
函数说明:计算给定数据集的经验熵(香农熵)

"""
def calcShannonEnt(dataSet):
    numEntires = len(dataSet)                        #返回数据集的行数
    labelCounts = {}                                #保存每个标签(Label)出现次数的字典
    for featVec in dataSet:                            #对每组特征向量进行统计
        currentLabel = featVec[-1]                    #提取标签(Label)信息
        labelCounts[currentLabel] = labelCounts.get(currentLabel,0)+1 #Label计数,如果标签(Label)没有放入统计次数的字典,添加进去

    shannonEnt = 0.0                                #经验熵(香农熵)
    for key in labelCounts:                            #计算香农熵
        prob = float(labelCounts[key]) / numEntires    #选择该标签(Label)的概率
        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                             #返回数据集和分类属性

"""
函数说明:按照给定特征划分数据集

Parameters:
    dataSet - 待划分的数据集
    index - 划分数据集的特征,代表第几个特征,如年龄。
    value - 需要返回的特征的值,代表该特征下的某个分类,如年龄下的中年。
"""
def splitDataSet(dataSet, index, value):     
    retDataSet = []                                        #创建返回的数据集列表
    for featVec in dataSet:                             #遍历数据集
        if featVec[index] == value:
    #将符合条件的添加到返回的数据集
            retDataSet.append(featVec)
    return retDataSet                                      #返回划分后的数据集

"""
函数说明:选择最优特征

Parameters:
    dataSet - 数据集
Returns:
    bestFeature - 信息增益最大的(最优)特征的索引值
"""
def chooseBestFeature(dataSet):
    numFeatures = len(dataSet[0]) - 1                    #特征数量
    baseEntropy = calcShannonEnt(dataSet)                 #计算数据集的香农熵
    bestInfoGain = 0.0                                  #信息增益
    bestFeature = -1                                    #最优特征的索引值
    for i in range(numFeatures):                         #遍历所有特征
        #获取dataSet的第i个所有特征
        featList = [item[i] for item in dataSet]
        uniqueVals = set(featList)                         #以列表创建set集合{},元素不可重复
        newEntropy = 0.0                                  #经验条件熵
        for value in uniqueVals:                         #计算信息增益
            subDataSet = splitDataSet(dataSet, i, value)         #subDataSet划分后的子集
            prob = len(subDataSet) / float(len(dataSet))           #计算子集的概率
            newEntropy += prob * calcShannonEnt(subDataSet)     #根据公式计算经验条件熵
        infoGain = baseEntropy - newEntropy                     #信息增益
        print("第%d个特征的增益为%.3f" % (i, infoGain))            #打印每个特征的信息增益
        if (infoGain > bestInfoGain):                             #计算信息增益
            bestInfoGain = infoGain                             #更新信息增益,找到最大的信息增益
            bestFeature = i                                     #记录信息增益最大的特征的索引值
    return bestFeature                                             #返回信息增益最大的特征的索引值

if __name__ == '__main__':
    dataSet, features = createDataSet()
    print("最优特征索引值:" + str(chooseBestFeature(dataSet)))

决策树算法实现步骤:

  • 计算经验熵;
  • 选择最优特征;
  • 递归。

常用的有CART, C4.5。

猜你喜欢

转载自blog.csdn.net/qq_42422981/article/details/84337219