【课程总结】Day4:信息论和决策树算法

前言

本章内容主要是学习机器学习中的一个重要模型:决策树,围绕决策树的应用,我们展开了解到:熵的定义、熵的计算、决策树的构建过程(基于快速降熵)、基尼系数等,从而使得我们对决策树有了直观认识。

熵的介绍

因为决策树主要思想是对数据集进行降熵,所以在了解决策树之前,有必要对再做下系统梳理。

熵的定义

  • 简言之,熵就是描述一个系统的混乱程度,熵越高,混乱程度越高。

  • 在一个孤立系统里,如果没有外力做功,其总混乱度(即熵)会不断增大

熵的含义

  • 熵越大,系统越混乱的
  • 熵越小,系统越有序的

例如:

生活上:如果房间(封闭系统)没有定期去打扫(外力引入),屋子会变得越来越乱(熵增),房间越乱熵越大。

工作上**:如果电脑桌面的文件夹(封闭系统)没有施加一定的归类归档工作(外力引入),文件夹及桌面会越来越乱(熵增),文件夹越乱熵越大。

联系到机器学习和信息论中:

  • 熵(Entropy)是信息理论中用于衡量系统无序程度或不确定性的指标。

  • 输出越确定越不混乱,越不确定越混乱。

    例如:考试做选择题,一个选择题有四个A、B、C、D选项;明确知道选择题选哪个,熵越小脑子越不混乱;不知道选哪个,4个选项看着都像,代表熵越大脑子越混乱。

  • 一个模型,在给定输入后,模型能够越肯定得输出结果,那么代表模型是一个好的模型;相反,如果不能确定的给定结果(甚至是瞎猜),那么就不能算做好的模型。

    例如:在鸢尾花的示例中,如果给定一个鸢尾花的数据让机器进行预测是哪种类型。如果模型能够99%确定给定数据是某一个类型,那么这个模型是我们需要的、是好的模型;如果模型给出的结果是1/3概率是1类型,1/3概率是2类型,1/3概率是3类型,那么这个实际是没有意义的。

  • 机器学习的训练过程本质上就是对抗熵的过程。

熵的计算

  • 对于一个包含多个类别的数据集,熵的计算公式为:

    H ( S ) = − ∑ i = 1 c p i log ⁡ 2 ( p i ) H(S) = - \sum_{i=1}^{c} p_i \log_2(p_i) H(S)=i=1cpilog2(pi)
    其中:
    H ( S ) H(S) H(S) 是数据集 S S S 的熵。
    c c c 是数据集中不同类别的数量。
    p i p_i pi 是数据集中第 $i $ 个类别所占比例。

代码实现

"""
    假定一个系统输出有2种情况:
    - A:[0.9, 0.1] -0.9概率输出第一种结果,0.1概率输出第二种
    - B:[0.6, 0.4] -0.6概率输出第一种结果,0.4概率输出第二种
    - C:[0.5, 0.5] -0.5概率输出第一种结果,0.5概率输出第二种

	问题:计算以上A、B、C的熵,看哪一种情况熵比较大
"""

import numpy as np

# 定义计算熵的函数
def entropy(probabilities):
    return -np.sum(probabilities * np.log2(probabilities))

# 定义每种情况的概率分布
A = np.array([0.9, 0.1])
B = np.array([0.6, 0.4])
C = np.array([0.5, 0.5])

# 计算每种情况的熵
entropy_A = entropy(A)
entropy_B = entropy(B)
entropy_C = entropy(C)

# 输出结果
print("情况A的熵:", entropy_A)
print("情况B的熵:", entropy_B)
print("情况C的熵:", entropy_C)


由上计算可知,C:[0.5, 0.5]的输出越不确定(一半概率输出第一种结果,一半输出第二种结果),所以其越混乱熵越大。

决策树

决策树的概念

决策树是一种用于解决分类问题的算法。它通过树状结构来表示各种决策规则,并根据输入数据的特征逐步进行决策,直到达到最终的预测结果。

一个例子

假设我们有一批如下的数据集:

ID有房者婚姻年收入是否拖欠贷款者
1单身10万
2已婚8万
3离异12万
4已婚15万
5单身6万
6已婚18万
7单身9万
8离异7万
9已婚14万
10单身5万

其中有房者、婚姻、年收入是特征(或者叫属性),是否拖欠贷款者是标签。

如果我们想通过这些特征来预测下一个数据是否会拖欠贷款,那么我们就可以构建一个决策树:

决策树的推理过程:

  • 每个节点都是一个判断过程

  • 直到找到叶子结点没有子节点后,即输出返回

决策树的预测

在Python中sklearn有提供相关的决策树库函数,我们仍然以鸢尾花的分类来使用决策树进行预测。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt

# 加载开源库中的iris数据集
X,y = load_iris(return_X_y=True)

# 切分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, 
                                                    shuffle=True, 
                                                    random_state=0) 

# 1,构建模型
dtc = DecisionTreeClassifier(criterion="entropy")

# 2,训练模型
dtc.fit(X=X_train, y=y_train)

# 3,预测数据
y_pred = dtc.predict(X=X_test)

# 4,查看准确率
acc = (y_pred == y_test).mean()
print("准确率:", acc)


# 使用 plot_tree 函数绘制决策树
plt.figure(figsize=(20, 20))
plot_tree(dtc, filled=True)
plt.show()

以上代码执行后,我们借助matplotlib和plot_tree将鸢尾花预测时的决策树以图形化的方式一并输出来了。

决策树的构建

决策树的应用(如上图)是相对比较简单的,而学习的重点所在:如何构建决策树

核心思想

通过快速降熵的方式,找到分割的节点,从而构建树的左右子集

构建步骤
  1. 选择最佳特征:

    • 对所有特征数据进行遍历,计算熵,找到熵降得最小的特征
  2. 分裂数据集:

    • 将数据集根据选择的最佳特征进行分割,分为左边和右边两部分子集。
  3. 递归构建:

    • 对每个子集重复1-2步骤,直到满足停止条件。

    • 停止条件可以是:达到最大深度、节点包含的样本数小于阈值等。

  4. 生成叶节点:

    • 当满足停止条件时,生成叶节点并确定叶节点的类别(或数值)。
构建过程推导(降熵entropy)

在上述的决策树中,我们通过plot_tree打印了已经构建的决策树。其中在根节点:

  • X[2] = 2.35,代表在特征2找到了最佳分裂点,最佳分裂值为1.581
  • Entropy = 1.581,代表此时的熵值为1.581
  • Samples = 120 ,代表此时的样本数量为120个

上述决策树通过代码来模拟决策过程,如下:

# 取特征的个数
n_features = X_train.shape[-1]

best_split_feature_idx = None
best_split_feature_value = None
best_split_entropy = float('inf')


# 遍历(0, 1, 2, 3)特征
for feature_idx in range(n_features):
    # ①特征值去重
    for value in set(X_train[:, feature_idx]):
        print('[iteration]分裂特征:', feature_idx)
        print('[iteration]分裂值:', value)

        # ②分裂值与特征对比,筛选出对应标签列
        # 左边的标签值
        y_left = y_train[(X_train[:, feature_idx] <= value)]
        entropy_left = get_entropy(y_left)
        print('[iteration]左边标签数据:', y_left)
        print('[iteration]左边的熵:', entropy_left)

        # 右边的标签值
        y_right = y_train[(X_train[:, feature_idx] > value)]
        entropy_right = get_entropy(y_right)
        print('[iteration]右边标签数据:', y_right)
        print('[iteration]右边的熵:', entropy_right)

        # ③计算融合的熵
        entropy_all = entropy_left * len(y_left) / len(X_train[:, feature_idx]) \
                    + entropy_right * len(y_right) / len(X_train[:, feature_idx])
        print('[iteration]融合的熵:', entropy_all)

        if entropy_all <= best_split_entropy:
            best_split_entropy = entropy_all
            best_split_feature_idx = feature_idx
            best_split_feature_value = value
            print(f'[result]找到了一个最好的分裂点:{best_split_feature_idx}, {best_split_feature_value}, {best_split_entropy}')

            # 打印左边和右边的样本数量和取值
            print('[result]左边样本数量:', len(y_left))
            print('[result]左边样本取值:', np.unique(y_left, return_counts=True))
            print('[result]右边样本数量:', len(y_right))
            print('[result]右边样本取值:', np.unique(y_right, return_counts=True))

        print('------------')

执行结果如下:

将以上输出的日志保存到本地的.log文件中,然后我们筛选出"[result]找到了一个最好的分裂点"这段日志:

通过上图可以看到,对120个数据集的每个特征进行遍历计算熵,计算之后找到了熵最小的分裂点有两个,分别为:

2, 1.7, 0.6713590373778532

3, 0.6, 0.6713590373778532

这两个分裂值的熵均为0.67135,一个是特征2类别下的特征值1.7,一个是特征3类别下的特征值0.6。对比plot_tree打印的决策树:

  • x[2] < = 2.35:即系统选择的是特征2下2.35(即:(1.7+3.0) / 2 = 2.35)这个最佳分裂点。

其过程用图来表示过程如下:

由此可知,决策树整体的运行方式为:

  • 构建模型:通过对训练的数据进行遍历计算,通过计算熵值找到最佳分裂点,然后递归计算直到达到停止条件,同时生成叶节点。

  • 预测数据:传入新的数据进行分类时,决策树进行特征的匹配计算从而找到对应的叶子节点。

    例如:假设需要预测一个[ 1, 2, 3, 4]的样本,那么决策树

    • 首先对特征2(即3)进行判断,发现3小于2.35不成立,向右走;
    • 然后对特征3(即4)进行判断,发现4<=1.75不成立,向右走;
    • 然后对特征2(即3)进行判断,发现3<=4.85成立,向左走;
    • 然后对特征0(即1)进行判断,发现1<=5.95成立,向左走达到叶子节点,返回类别1

构建过程推导(基尼系数gini)
基尼系数的定义

定义:基尼系数(Gini Index)是决策树算法中用于衡量数据集纯度的指标之一。

基尼系数的推导
  • 假设有三个概率[p1, p2, p3]

    • 计算其熵值方法为:

      -( p1 * log2(p1) + p2 * log2(p2) + p3 * log2(p3) ) →

      -p1 * log2(p1) - p2 * log2(p2) - p3 * log2(p3) ) →

      p1 * log2(1/p1) + p2 * log2(1/p2) + p3 * log2(1/p3) ) ~

      p1 * ( 1 - p1) + p2 * (1 - p2) + p3 * (1 - p3)

基尼系数的意义

基尼系数本质上是一种工程上对熵计算的数学化简,可以省去较为麻烦的log2(1/P)的计算,取而代之的变为P * (1-P),从而降低工程的计算代价。

以上决策树改为使用gini系数来进行构建:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt

# 加载开源库中的iris数据集
X,y = load_iris(return_X_y=True)

# 切分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, 
                                                    shuffle=True, 
                                                    random_state=0) 

# 1,构建模型
dtc = DecisionTreeClassifier(criterion="gini")

# 2,训练模型
dtc.fit(X=X_train, y=y_train)

# 3,预测数据
y_pred = dtc.predict(X=X_test)

# 4,查看准确率
acc = (y_pred == y_test).mean()
print("准确率:", acc)


# 使用 plot_tree 函数绘制决策树
plt.figure(figsize=(20, 20))
plot_tree(dtc, filled=True)
plt.show()

运行结果:

模拟决策树构建过程改为gini系数如下:

import numpy as np

# 计算传入的logits概率
# 计算方法:
# 1、对logits进行去重
# 2、计算每个label(例如:0,1,2)出现的次数
# 3、概率=出现次数/总的logits个数
def get_gini(logits = [2, 1, 0, 2, 2, 1, 0, 2]):

    # 类型转换为np数组
    logits = np.array(logits)

    # 获得不同类型的标签数量
    num_logits = len(logits)

    # 特殊处理:没有样本或者样本类型都一样,则混乱程度一样,熵为0
    if num_logits < 2:
        return 0

    # 计算对应标签的概率,即:概率 = 出现次数/总的个数
    probs = np.array([(logits == label).sum() for label in set(logits)]) / len(logits)

    # 计算系统的熵
    gini = (probs * (1 - probs)).sum()

    print("[get_entropy]传入的logits值为:", logits)
    print("[get_entropy]去重后的label为:", set(logits))
    print("[get_entropy]每个lable的概率为:", probs)
    print("[get_entropy]计算得到的gini为:", gini)

    return gini

# 取特征的个数
n_features = X_train.shape[-1]

best_split_feature_idx = None
best_split_feature_value = None
best_split_gini = float('inf')


# 遍历(0, 1, 2, 3)特征
for feature_idx in range(n_features):
    # ①特征值去重
    for value in set(X_train[:, feature_idx]):
        print('[iteration]分裂特征:', feature_idx)
        print('[iteration]分裂值:', value)

        # ②分裂值与特征对比,筛选出对应标签列
        # 左边的标签值
        y_left = y_train[(X_train[:, feature_idx] <= value)]
        gini_left = get_gini(y_left)
        print('[iteration]左边标签数据:', y_left)
        print('[iteration]左边的熵:', gini_left)

        # 右边的标签值
        y_right = y_train[(X_train[:, feature_idx] > value)]
        gini_right = get_gini(y_right)
        print('[iteration]右边标签数据:', y_right)
        print('[iteration]右边的熵:', gini_right)

        # ③计算融合的熵
        gini_all = gini_left * len(y_left) / len(X_train[:, feature_idx]) \
                    + gini_right * len(y_right) / len(X_train[:, feature_idx])
        print('[iteration]融合的熵:', gini_all)

        if gini_all <= best_split_gini:
            best_split_gini = gini_all
            best_split_feature_idx = feature_idx
            best_split_feature_value = value
            print(f'[result]找到了一个最好的分裂点:{best_split_feature_idx}, {best_split_feature_value}, {best_split_gini}')

            # 打印左边和右边的样本数量和取值
            print('[result]左边样本数量:', len(y_left))
            print('[result]左边样本取值:', np.unique(y_left, return_counts=True))
            print('[result]右边样本数量:', len(y_right))
            print('[result]右边样本取值:', np.unique(y_right, return_counts=True))

        print('------------')

运行对比,gini系数的计算与plot_tree输出一致。

决策树的意义

决策树可以用于进行特征筛选。

例如:通过鸢尾花分类问题对比发现,在决策树计算过程中,通过dtc.feature_importances_可以看到特征1的重要性为0,基本上没有什么作用;而特征3比较重要。

优点:解释性比较好,可以对特征进行重要性排序,模型可大可小(可以进行剪枝)

本章小结

  • 熵是衡量一个系统的混乱程度。熵越大,系统越混乱的;熵越小,系统越有序的。
  • 一个模型输出越确定越不混乱,越不确定越混乱。
  • 决策树是一种用于解决分类问题的算法,它通过一定的规则对每一个节点进行判断,直到找到叶子节点后输出返回。
  • 基于降熵的思想,决策树在构建过程中,对数据进行遍历计算熵,找到熵降得最小的,然后将该熵对应的值作为分裂值,分为左边和右边两部分,直到结束。
  • 为了简化熵的计算,也可以使用gini系数来进行计算,从而简化工程计算代价。
  • 除了决策树进行预测之外,也可以用于进行特征筛选。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/665313.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

U盘损坏打不开?数据恢复攻略全解析

随着信息技术的飞速发展&#xff0c;U盘已成为我们日常工作和生活中不可或缺的数据存储工具。然而&#xff0c;当U盘突然损坏&#xff0c;无法打开时&#xff0c;我们往往会陷入焦虑和无助之中。本文将为大家详细解析U盘损坏打不开的原因&#xff0c;并提供两种有效的数据恢复方…

【stm32】stm32f407 ch340下载

一、接线 1、ch340 Vcc短接3v3 5v---------5v GND-----GND TX ------RX RX --------TX 2、stm32F407 如上图&#xff0c;我们需要进入isp下载模式&#xff0c;接线图如下 二、下载 使用FlyMcu选择你要下载的程序文件中的.hex文件&#xff0c; 然后配置图如下&#xff1…

5月安全月报 | 钓鱼事件频发,OKLink带你开启“防钓”模式

本月全网安全事件所造成的损失环比上升 27.27%&#xff0c;钓鱼与诈骗事件占比 60% 以上。 安全意识是您保护数字资产的第一道防线&#xff0c;OKLink 提供 40 头部区块链浏览器与一站式查询入口以及地址监控、代币授权查询和地址健康度等工具&#xff0c;为您的资产安全保驾护…

使用CS抓取WIN2012明文密码

目录 实验概述&#xff1a; 开始实验&#xff1a; 实验准备&#xff1a; 打开CS&#xff1a; 生成木马控制wind2012&#xff1a; 抓取明文密码&#xff1a; 实验概述&#xff1a; win2012及win10版本是不允许将明文密码储存在内存中的&#xff0c;此时我们…

大量path计算优化方案

1.影响path基础属性数据做key缓存&#xff0c;缓存的path应去除坐标变换&#xff0c;归一化。基础属性应满足CAB, BC-A 2.高频path操作以&#xff08;keykey操作&#xff09;做新key缓存。 3.高频修改高级属性&#xff0c;以新key属性变更做新key缓存。 4.key与id做中转映射&am…

【每日刷题】Day52

【每日刷题】Day52 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 2965. 找出缺失和重复的数字 - 力扣&#xff08;LeetCode&#xff09; 2. 350. 两个数组的交集 II …

C# FTP/SFTP 详解及连接 FTP/SFTP 方式示例汇总

文章目录 1、FTP/SFTP基础知识FTPSFTP 2、FTP连接示例3、SFTP连接示例4、总结 在软件开发中&#xff0c;文件传输是一个常见的需求。尤其是在不同的服务器之间传输文件时&#xff0c;FTP&#xff08;文件传输协议&#xff09;和SFTP&#xff08;安全文件传输协议&#xff09;成…

dolphinscheduler docker部署海豚mysql版本,docker重新封装正在运行服务为镜像

1.官方文档&#xff1a; https://dolphinscheduler.apache.org/zh-cn/docs/3.2.1/guide/installation/standalone#%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E5%BA%93 2.github: dolphinscheduler/docs/docs/zh/guide/howto/datasource-setting.md at 3.2.1-release apache/do…

【R基础】如何开始学习R-从下载R及Rstudio开始

文章目录 概要下载R流程下载Rstudio流程下载完成-打开 概要 提示&#xff1a;如何开始学习R-从下载R及Rstudio开始&#xff0c;此处我只是想下载指定版本R4.3.3 下载R流程 链接: R官网 文件下载到本地 下载文件展示 按照向导指示安装 下载Rstudio流程 链接: Rstudio官网…

深度学习-语言模型

深度学习-语言模型 统计语言模型神经网络语言模型语言模型的应用序列模型&#xff08;Sequence Model&#xff09;语言模型&#xff08;Language Model&#xff09;序列模型和语言模型的区别 语言模型&#xff08;Language Model&#xff09;是自然语言处理&#xff08;NLP&…

AI预测福彩3D采取888=3策略+和值012路一缩定乾坤测试5月31日预测第7弹

昨天的3D已命中&#xff01;今天继续基于8883的大底&#xff0c;使用尽可能少的条件进行缩号。好了&#xff0c;直接上结果吧~ 首先&#xff0c;888定位如下&#xff1a; 百位&#xff1a;7,6,5,8,9,3,2,0 十位&#xff1a;3,4,5,2,1,7,8,9 …

20240531在飞凌的OK3588-C开发板上跑原厂的Buildroot测试USB摄像头

20240531在飞凌的OK3588-C开发板上跑原厂的Buildroot测试USB摄像头 2024/5/31 20:04 USB摄像头分辨率&#xff1a;1080p&#xff08;1920x1080&#xff09; 默认编译Buildroot的SDK即可点亮USB摄像头。v4l2-ctl --list-devices v4l2-ctl --list-formats-ext -d /dev/video74 …

【UnityShader入门精要学习笔记】第十六章 Unity中的渲染优化技术 (下)

本系列为作者学习UnityShader入门精要而作的笔记&#xff0c;内容将包括&#xff1a; 书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更&#xff0c;有始无终 我的GitHub仓库 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 减少需要处…

【Linux】操作系统之冯诺依曼体系

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; Linux &#x1f389;其它专栏&#xff1a; C初阶 | C进阶 | 初阶数据结构 小伙伴们大家好&#xff0c;本片文章将会讲解 操作系统中 冯诺依曼体系 的相关内容。 如果看到最后您觉得这篇文…

基于编译型语言鲲鹏应用开发小技巧

编译型语言应用执行过程 大部分应用可以通过重新编译即可移植到鲲鹏平台 预处理命令: gcc -E hello.c -o hello.i&#xff0c;预处理完成后使用命令: cat hello.i可以看到预处理后的代码 编译命令: gcc -s hello.i -o hello.s 汇编命令: gcc -c hello.c -o hello.o 链接处理…

接口测试之XML响应断言

目录 XPath 基本语法XML 响应结果解析XML 响应结果断言 XML 响应数据 如何提取 AddResult 中的值&#xff1f; <soap:Body><AddResponse xmlns"http://tempuri.org/"><AddResult>4</AddResult></AddResponse> </soap:Body> …

SpringBoot中MyBatisPlus的使用

MyBatis Plus 是 MyBatis 的增强工具&#xff0c;提供了许多强大的功能&#xff0c;简化了 MyBatis 的使用。下面是在 Spring Boot 中使用 MyBatis Plus 的步骤&#xff1a; 添加依赖&#xff1a;在 Maven 或 Gradle 的配置文件中添加 MyBatis Plus 的依赖。 配置数据源&#…

AI换脸FaceFusion一键云部署指南

大家好&#xff0c;从我开始分享到现在&#xff0c;收到很多朋友的反馈说配置很低玩不了AI。本篇是一个云端部署AI项目的指南&#xff0c;帮助大家在云端进行AI项目的部署。我会从云平台的选择、代码部署、保存镜像几个方面进行详细的介绍。没有代码基础的小白也不用担心&#…

QT系列教程(6) 几种标准对话框

几种标准对话框 本文介绍几种标准对话框&#xff0c;都是Qt封装好的&#xff0c;我们先创建一个界面&#xff0c;添加几个按钮&#xff0c;然后分别在几个按钮的回调函数里添加创建不同对话框的逻辑 颜色对话框 颜色对话框用来选择颜色&#xff0c;创建后会显示各种颜色和透明…

神经网络-------人工神经网络

一、什么是神经网络和神经元 人工神经网络&#xff08;英语&#xff1a;Artificial Neural Network&#xff0c;ANN&#xff09;&#xff0c;简称 神经网络&#xff08;Neural Network&#xff0c;NN&#xff09;或 类神经网络&#xff0c;是一种模仿生物神经网络&#xff08;…