决策树中的信息熵+鸢尾花数据集举例

1 决策树

决策树算法是最简单也是最成功的机器学习方法之一。
决策树(DT)由内部和外部节点组成。节点之间的相互连接称为树的分支。内部节点是决策单元根据不同的节点决定下一个子节点的访问相关变量的可能值;外部节点也称为叶子节点,是分支的终止节点,它没有子节点,并且与给定数据的类标签具有一定的关联关系。决策树是树中的一组规则结构,其中的每个分支都可以解释为与之关联的决策规则沿着这个分支访问的节点。
对于决策树,可以理解为它是一个由if-else规则集构建出来的机器学习模型。if-else规则的判断依赖于信息熵,或者说信息熵这一指标就是决策树进行分类或者回归的决策依据。

2 鸢尾花数据集的信息熵

熵代表一个系统的杂乱程度,熵越大,系统越杂乱。对一个数据集中数据的分类就是使得该数据集熵减小的过程。决策树算法就是一个划分数据集的过程。划分数据集的原则就是:将无序的数据变得更加有序。我们假设得到的数据是有用的信息,处理信息的一种有效的方法就是利用信息论进行熵的计算。
针对具有 m m m个类别的数据集中的每一个属性,信息熵的计算公式为公式(1):
E = ∑ i = 1 m p i ∗ l o g p i E=\sum_{i=1}^mp_i*logp_i E=i=1mpilogpi
其中 p i p_i pi表示第 i i i个类别样本数量的占比。由于属性可以分为连续属性和离散属性, p i p_i pi的计算也不相同。由于连续属性信息熵的计算较为复杂,并且经过离散化后的连续属性计算方法与直接计算离散属性一致,所以本次以计算鸢尾花数据集连续属性为例进行介绍。
鸢尾花数据集共有四个属性三种类别,共150组数据,如下图所示。由于鸢尾花数据集的四个属性均为连续属性,所以在计算信息熵的时候,使用C4.5算法计算连续属性的信息熵的值。
在这里插入图片描述
针对每个属性,首先对其进行离散化处理。由于鸢尾花数据集分为三类,所以需要在每个连续属性中寻找两个分割点,使得在该分割点作用下得到的信息增益最大,即分割后的信息熵最小。由C4.5算法可知,在对原始连续属性排序的基础上,分割点的划分集合为公式(2):
在这里插入图片描述
但是由于排序后的数据中相同大小的数据较多,为了方便决策树划分以及提高划分的科学性,使用如下所示公式(3)加权平均分作为划分集合点:
在这里插入图片描述
其中 ω i ω i + 1 \omega^i\omega^{i+1} ωiωi+1为公式(4):
在这里插入图片描述
n u m b e r ( a i ) number(a^i) number(ai)代表数据相同元素 a i a^i ai的个数。
在上述分割点集合确定的基础上,使用组合的方式获得所有可能的分割点组合。对于每组分割点,得到被分割点分割后的三个连续片段,再利用公式(1)分别对三个片段求解信息熵,并以三个信息熵的加权平均和表示为最终得到的信息熵。
对连续属性处理的核心是寻找使得属性熵最小的分割点。以鸢尾花数据集为例,首先对其属性值进行排序,再以式(3)、(4)所示的公式求相邻属性值的加权平均数获取分割点集合;按顺序每次从分割点集合中拿出两个分割点进行计算,对于分成的三段连续区间的每一段区间,利用公式(1)分别计算其信息熵的值。最后,对得到的三段区间信息熵的值进行按照区间数量占比的权重进行加权平均,从而得到每组分割点的熵值。找到熵值最小的一组分割点,就可以实现将连续数据离散化,从而实现连续属性的分类。对于更一般连续属性离散化过程,只需将分割后的区间数量与样本标签类别数一致即可。
对于混合型属性,既包含连续属性,又包含离散属性,对其进行决策树分类时的核心处理思想是在用C4.5建立决策树时,需要先区分出是哪一种属性,再对属性计算信息增益比以求出最佳分割属性和最佳分割点。其中,对混合数据进行离散化有两个关键点:
(1)在构建决策树前,分别使用连续属性和离散属性熵计算的方法得到各属性的熵最小值,提前将连续属性的分割点找出。
(2)构建决策树时,当节点处信息增益算得连续属性的增益较大时,节点生成的子节点数与类别数一致;当节点处信息增益算得离散属性的增益较大时,节点生成的子节点数与离散属性种类数一致。
talk is cheap,code如下:

mport math
from collections import Counter
import numpy as np


# 计算熵
def calculate_entropy(step):
    res = -sum([(step[i] / sum(step)) * math.log((step[i] / sum(step)), 2) if step[i] != 0 else 0 for i in range(0, 3)])
    return res


#  计算连续属性的信息熵
def getentropy(sort_list, sort_label, cutoff1, cutoff2):
    assert cutoff1 not in sort_list
    assert cutoff2 not in sort_list
    assert cutoff2 > cutoff1
    assert sort_list[0] <= sort_list[-1]
    step1 = [0,0,0]  # < cutoff1
    step2 = [0,0,0]  #  1-2
    step3 = [0,0,0]  #  2-
    for i in range(len(sort_list)):
        if sort_list[i] < cutoff1:
            if sort_label[i] == 'setosa':
                step1[0] += 1
            elif sort_label[i] == 'versicolor':
                step1[1] += 1
            elif sort_label[i] == 'virginica':
                step1[2] += 1
        elif sort_list[i] <cutoff2 and sort_list[i] > cutoff1:
            if sort_label[i] == 'setosa':
                step2[0] += 1
            elif sort_label[i] == 'versicolor':
                step2[1] += 1
            elif sort_label[i] == 'virginica':
                step2[2] += 1
        else:
            if sort_label[i] == 'setosa':
                step3[0] += 1
            elif sort_label[i] == 'versicolor':
                step3[1] += 1
            elif sort_label[i] == 'virginica':
                step3[2] += 1
    w1 = sum(step1)/150
    w2 = sum(step2)/150
    w3 = sum(step3)/150
    entropy = w1*calculate_entropy(step1) + w2*calculate_entropy(step2) + w3*calculate_entropy(step3)
    if round(cutoff1,3)==0.95 and round(cutoff2,3)==1.786:
        print("属性4的最小分割:", step1, step2, step3)
    return entropy


# 选择分割点
def select_cutoff(feature_list, feature_label):
    # print(feature_list)
    sort_index = np.argsort(feature_list)
    # print(sort_index)
    # 排序
    sort_feature = [0 for i in feature_list]
    sort_label = [0 for i in feature_label]
    for i in range(len(sort_index)):
        sort_feature[i] = feature_list[sort_index[i]]
        sort_label[i] = feature_label[sort_index[i]]
    # print(sort_feature,"\n", sort_label)
    # 获取分界点1  2
    ct = Counter(sort_feature)
    removesame = sorted(ct.most_common())  # 从小到大排序
    cut_off = []
    for i in range(len(removesame)-1):
        w1 = removesame[i][1]/(removesame[i][1]+removesame[i+1][1])
        w2 = removesame[i+1][1]/(removesame[i][1]+removesame[i+1][1])
        cut_off.append(w1*removesame[i][0]+w2*removesame[i+1][0])
    cut_off_choose = []
    for i in range(len(cut_off)-1):
        for j in range(i+1, len(cut_off)):
            cut_off_choose.append((cut_off[i], cut_off[j]))  # 元组
    # 逐次计算熵
    res = []
    for cutoff in cut_off_choose:
        res.append(getentropy(sort_feature, sort_label, cutoff[0], cutoff[1]))
    return cut_off_choose, res


def get_min_entropy_cutoff(cut_off_choose, res):
    res_ = [round(eve,5) for eve in res]
    tp = min(res_)
    i = res_.index(tp)
    res_list = [round(eve,3) for eve in list(cut_off_choose[i])]
    return res_list

# 获取最优分割点
def main_of_get_cut_off():
    # read iris data-set as txt.
    with open(r"iris.txt","r",encoding="utf-8") as file:
        all_data = [line.split() for line in file]
    attribute_name = all_data[0]
    data = [[float(number) for number in sample[1:-1]] for sample in all_data[1:]]
    labels = [sample[-1][1:-1] for sample in all_data[1:]]
    sepal_length = [eve[0] for eve in data]
    sepal_width= [eve[1] for eve in data]
    petal_length= [eve[2] for eve in data]
    petal_width= [eve[3] for eve in data]
    # 依次选择四个特征的值进行处理,选择每个特征的分割点
    cut_off_choose1, res1 = select_cutoff(sepal_length, labels)
    cut_off_choose2, res2 = select_cutoff(sepal_width, labels)
    cut_off_choose3, res3 = select_cutoff(petal_length, labels)
    cut_off_choose4, res4 = select_cutoff(petal_width, labels)
    print("四个属性的最小熵:", min(res1), min(res2), min(res3), min(res4))
    res = [get_min_entropy_cutoff(cut_off_choose1, res1),get_min_entropy_cutoff(cut_off_choose2, res2),
            get_min_entropy_cutoff(cut_off_choose3, res3),get_min_entropy_cutoff(cut_off_choose4, res4)]
    return res, data, labels


if __name__ == '__main__':

    razors, data, labels_ = main_of_get_cut_off()
    labels = []
    print("四个属性的分割点(按顺序):", razors)

使用上述方法计算鸢尾花数据四个连续属性的熵:
在这里插入图片描述

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值