决策树算法处理分类及回归问题的原理及python代码实现

2023-11-08

1. 决策树原理介绍

        通俗的理解,决策树就是对样本集根据某一个维度d和某一个阈值v进行二分,得到二叉树,即为决策树。通过样本训练计算出维度d和阈值v,即可对预测数据进行分类,如果对二叉树的各子节点value值求平均,将平均值赋予待分类样本,即完成待测样本的回归预测。

1.1 决策边界的划分

        最佳阈值能够最大限度的把样本区分开,让其各自分类中单一类别比重最大,使其分类确定性更大。阈值的选取是来自特征向量相邻两个值的平均值,直观的看如上图所示。图中先以x=2.4作为分割线,小于这个阈值的完全属于A类,大于这个阈值的完全属于非A类,接下来再对非A值进行分割,以y=1.8作为分割线,小于这个阈值的属于B类比重最大,大于这个阈值的属于C类比重最大。

上述思想用代码实现如下所示,入参

X::样本输入空间

y:样本输出空间

d:分割维度

value:分割阈值

出参:

X[index_a]:分割左节点的输入空间

X[index_b]:分割右节点的输入空间

y[index_a]:分割左节点的输出空间

y[index_b]:分割右节点的输出空间

def split(X, y, d, value):
    index_a = (X[:, d] <= value)
    index_b = (X[:, d] > value)
    return X[index_a], X[index_b], y[index_a], y[index_b]

1.2 不确定性的度量        

        从图中可以直观的找到这个分割阈值,使其分类单一比重最大。但实际应用中, 如何找到这个阈值,我们是否有一个可以量化的评判标准呢?

        可以通过信息熵和基尼系数量化的评判每一次分割对样本集的确定性进行度量,单一性越好,能够最大限度的分开两个类别,其信息熵和基尼系数值越小,否则越大。我们可以通过网格搜索的思想,对所有样本各个维度的分割点进行信息熵或基尼系数的计算,找到最小值,从而确定每个节点在哪个维度做划分,某个维度在哪个值上做分割。

信息熵的公式如下:

H=-\sum_{i=1}^{k}\rho _{i}log(\rho _{i})

基尼系数的公式如下:

G=1-\sum_{i=1}^{k}\rho_{i}^{2}

        如果某一分割线能够完全将样本中的某一类别区分开,即某节点中的类别单一性最佳,确定度最大,为100%纯单一类别。根据以上公式可得信息熵和基尼指数值均为0。使用代码表示以上公式如下所示:

def entropy(y):
    counter = Counter(y)
    res = 0.0
    for num in counter.values():
        p = num / len(y)
        res += -p * log(p)
    return res

def gini(y):
    counter = Counter(y)
    res = 1.0
    for num in counter.values():
        p = num / len(y)
        res -= p**2
    return res

1.3 决策边界的寻找   

        通过阈值对样本分类后,可将分类中的输出空间代入以上方法入参,即可计算得出此分类样本左右节点的信息熵或基尼系数。

        假如先以x轴特征向量为判断条件,将所有样本横坐标从小到大依次排列,所有相邻两个样本值x^{(i)}x^{(i+1)}的中值\frac{x^{(i)}+x^{(i+1)}}{2}依次作为阈值分别进行分割,计算分割后两个类别(左右节点数据集)的信息熵或基尼系数。同理,以y轴特征向量为判断条件,依次计算信息熵或基尼系数。最后,将左右节点的信息熵或基尼系数相加,遍历所有维度所有阈值,找到最小值。此时的维度和阈值作为分隔点分割出A类和非A类,然后用同样的方法对非A类再进行分隔,得到B类和C类。

        值得注意的是,先以x轴还是y轴进行分隔,最后的决策边界可能完全不同,因其分割线只能是某个向量的值,有可能在多个维度上寻找到相同的最小值,又因决策树无法在一次分隔中同时兼顾多个向量,所以导致最后的决策边界会因遍历维度的先后顺序不同而不同。其具体代码实现如下:

def try_split(X, y):
    best_entropy = float('inf')
    best_d, best_v = -1, -1
    for d in range(X.shape[1]):  # 列,维度,特征 数量
        sorted_index = np.argsort(X[:, d])
        for i in range(1, len(X)):
            if X[sorted_index[i], d] != X[sorted_index[i - 1], d]:
                v = (X[sorted_index[i], d] + X[sorted_index[i - 1], d]) / 2
                X_l, X_r, y_l, y_r = split(X, y, d, v)
                e = entropy(y_l) + entropy(y_r)
                if e < best_entropy:
                    best_entropy, best_d, best_v = e, d, v
    return best_entropy, best_d, best_v

1.4 自编决策树的验证

        以鸢尾花数据集为例,根据上述方法,进行试验,进行深度为2的切割,数据准备及相关包引入代码:

import numpy as np
import pandas as pd
from sklearn import datasets
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor
from collections import Counter
from math import log


# 鸢尾花数据集准备
def dataInit(type="iris"):
    if type == "iris":
        iris = datasets.load_iris()
        X = iris.data[:, 2:]  # 使用后两个特征
        y = iris.target  # 三分类
    elif type == "boston":
        data_url = "http://lib.stat.cmu.edu/datasets/boston"
        boston = pd.read_csv(data_url, sep="\s+", skiprows=22, header=None)
        data = np.hstack([boston.values[::2, :], boston.values[1::2, :2]])
        target = boston.values[1::2, 2]
        X, y = data, target
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
    return X_train, X_test, y_train, y_test, X, y

        首先对样本集进行第一层二叉分割,由于左节点信息熵和基尼系数为0,故不需要对左节点进行第二层划分,右节点基尼系数为0.69,还比较偏大,进行第二次划分,代码实现如下所示:

def myDecisionTree():
    X = dataInit(type="iris")[4]
    y = dataInit(type="iris")[5]
    # 第一个节点的阈值的计算
    best_entropy, entropy_left, entropy_right, best_d, best_v = try_split(X, y)
    print("第一个节点的阈值的计算 best_entropy = {},entropy_left = {} ,entropy_right = {}, best_d = {}, best_v = {}".format(
        best_entropy, entropy_left, entropy_right, best_d, best_v))
    # 根据阈值切分第一层左右子节点
    X1_left, X1_right, y1_left, y1_right = split(X, y, best_d, best_v)

    # 对第一层右节点进行二次分类,并计算其分类阈值
    best_entropy2, entropy_left2, entropy_right2, best_d2, best_v2 = try_split(X1_right, y1_right)
    print("第二个节点的阈值的计算 best_entropy2 = {},entropy_left2 = {} ,entropy_right2 = {}, best_d2 = {}, best_v2 = {}".format(
        best_entropy2, entropy_left2, entropy_right2, best_d2, best_v2))
    # 根据阈值切分得到第二层左右子节点
    X2_left, X2_right, y2_left, y2_right = split(X1_right, y1_right, best_d2, best_v2)

2. 基于sklearn的决策树实现

        上述是通过决策树的原理进行手敲代码实现,但在实际应用中,笔者还是建议使用sklearn封装的方法进行实现,手敲决策树只是为了方便读者理解其实现原理,封装的代码做了更多的性能优化和超参数设置。具体代码如下:

def decisionTreeClassification():
    # 基于信息熵的决策树分类
    X_train, X_test, y_train, y_test, X, y = dataInit(type="iris")
    dt_clf = DecisionTreeClassifier(max_depth=2, criterion="entropy", random_state=42)
    dt_clf.fit(X_train, y_train)
    train_score = dt_clf.score(X_train, y_train)
    test_score = dt_clf.score(X_test, y_test)
    print("基于信息熵的决策树分类 训练集得分 = {}, 测试集得分 = {}.".format(train_score, test_score))

    # 基于基尼系数的决策树分类
    dt_clf = DecisionTreeClassifier(max_depth=2, criterion="gini", random_state=42)
    dt_clf.fit(X_train, y_train)
    train_score = dt_clf.score(X_train, y_train)
    test_score = dt_clf.score(X_test, y_test)
    print("基于基尼系数的决策树分类 训练集得分 = {}, 测试集得分 = {}.".format(train_score, test_score))

        决策树解决回归问题,以房价数据集为例,调用方法如下所示:

# 决策树回归
def decisionTreeRegression():
    X_train, X_test, y_train, y_test, X, y = dataInit(type="boston")
    dt_reg = DecisionTreeRegressor()
    dt_reg.fit(X_train, y_train)
    train_score = dt_reg.score(X_train, y_train)
    test_score = dt_reg.score(X_test, y_test)
    print("决策树回归 训练集得分 = {}, 测试集得分 = {}.".format(train_score, test_score))

3. 决策树常用超参数介绍

3.1 DecisionTreeClassifier的参数

-criterion:衡量分割质量的指标。默认为"gini"表示基尼系数,也可以设置为entropy表示信息熵
-splitter:选择分裂节点的策略。默认为"best"表示最优分裂,也可以设置为random"表示随机分裂
-max_depth:树的最大深度。默认为 None 表示不限制树的深度,也可以设置为整数来限制树的深度
-min_samples_split :分裂节点所需的最小样本数。默认为2,表示至少需要2个样本才能进行分裂,可以设置为整数或浮点数来调整这个值。
-min_samples_leaf:叶子节点所需的最小样本数。默认为1,表示叶子节点至少需要一个样本,可以设置为整数或浮点数来调整这个值。
-min_weight_fraction leaf:叶子节点的最小权重比例。默认为0,表示不考虑叶子节点的权重,可以设置为浮点数来调整这个值
-max_features:每个节点分裂时考虑的特征数。可以设置为整数或浮点数,表示考虑的特征数目或比例。默认为"auto"表示考虑所有特征
-random state:随机种子。如果设置了随机种子,每次练都会得到相同的结果。默认为 None,表示使用系统默认的随机种子
-maxleaf_nodes:最大叶子节点数。默认为None,表示不限制叶子节点数目,可以设置为整数来限制叶子节点数目
-class_weight:类别权重。可以设置为"balanced"表示根据训练样本自动调节类别权重,也可以设置为一个字典来指定每个类别的权重
-ccp_alpha:剪枝系数。默认为 0,表示不剪枝,可以设置为一个非负浮点数来进行剪枝。

3.2 DecisionTreeRegressor的参数

-criterion:这个参数指定了决策树的分裂策略, {“squared_error”平均平方误差, “friedman_mse”平均平方误差与Friedman改进得分, “absolute_error”平均绝对误差, “poisson”减少泊松偏差}, default=”squared_error”
-splitter:这个参数指定了决策树的分裂策略,可以选择“best”(最优)或“random”(随机)。
-max_depth:这个参数指定了决策树的最大深度,用于控制决策树的复杂度
-min_samples_split:这个参数指定了最小分裂样本数,用于控制决策树的分裂策略。
-min samples_leaf:这个参数指定了最小叶子节点样本数用于控制决策树的剪枝策略
-max_features:这个参数指定了每个节点可选的特征数,用于控制决策树的复杂度和泛化能力。
-random_state:这个参数指定了随机种子,用于控制每次运行的结果是否一致。

4 总结

        本文讲解了决策树的原理以及信息熵和基尼系数对决策树分类的作用,并通过手写代码进一步阐述了决策树的实现原理。最后通过调用sklearn封装的函数使用决策树算法解决分类及回归问题,以及函数中诸多超参数的含义。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

决策树算法处理分类及回归问题的原理及python代码实现 的相关文章

随机推荐

  • Scala 正则表达式

    Scala 正则表达式 Scala 通过 scala util matching 包中的 Regex 类来支持正则表达式 以下实例演示了使用正则表达式查找单词 Scala import scala util matching Regex o
  • chatglm docker镜像,一键部署chatglm本地知识库

    好久没有写文章了 今天有空 记录一下chatglm本地知识库的docker镜像制作过程 核心程序是基于 闻达 开源项目 稍作改动 镜像可以直接启动运行 大家感兴趣可以进入镜像内部查看 代码位于 app 目录下 一 制作镜像 docker t
  • ISTQB认证工程师学习笔记(5)——测试管理

    测试管理的学习目标 测试组织 测试计划和估算 测试监督与控制 配置管理 风险和测试 缺陷管理 测试组织 独立测试 测试任务可以由具体指定的测试人员完成 也可以由其他角色人员完成 比如客户 由于作者和测试员的认知取向不同 一定程度的独立性可以
  • SpringCloud Alibaba Nacos作为配置中心不生效问题

    在使用Springcloud Alibaba 的Nacos作为配置中心时 遇到了在配置中心中提交相关配置后但配置还是从本地获取 没有从nacos中获取的情况 可能是如下原因导致 1 需要自行新建bootstrap properties并配置
  • 人工稚能之sklearn分类

    分类算法和聚类比较类似 都是将输入数据赋予一个标签类别 区别是分类算法的分类是预先确定的 有明确含义的 而聚类的标签是从输入数据本身的分布中提取出来的一种抽象的类别 聚类是无监督算法 而分类是有监督的 除了输入数据x外 还有标签y 分类算法
  • WSL 更新NVIDIA 驱动 安装CUDA

    WSL 一定要使用WSL2 我选择的linux系统是ubuntu22 04 在微软应用商店安装的 安装完成之后可以通过 wsl l v查看 NVIDIA 驱动 WSL 中不要直接安装linux版的显卡驱动 而是需要在windows中安装驱动
  • 动态知识图补全问题

    4 19 4 23 动态信息 1 Dual Quaternion Knowledge Graph Embeddings 本文应该是静态方法 距离公式和旋转公式的一个统一框架 提出一个新的映射空间 Dual Quaternion space
  • 民数记研读1——于宏洁

    民数记研读 于宏洁 1 西乃山下 一 第一次数点百姓 二 各支派安营 三 前行 四 银号 2 几种重要的人 一 利未人 二 拿细耳人的条例 三 首领 3 管与教 一 从荣耀角度来看神的管教 二 在神的管教中 要注意的几个点 三 民数记中十次
  • Apple 的 plist 编辑器入门指南:基础操作与高级功能详解

    PlistEdit Pro是一款专为macOS编写的最高级属性列表Plist编辑器 对于Mac和IOS开发人员来说 编写应用程序时必须编辑各种列表文件 PlistEdit Pro通过提供直观且功能强大的界面 使编辑这些文件更加容易 它不仅能
  • 深度学习机器学习目标检测

    一 目标检测 1 深度学习开发流程 2 应用案例 3 目标检测算法基本流程 二 机器学习 1 机器学习算法能解决那些问题 分类问题 图像识别 垃圾邮件识别 回归问题 各种预测 房价 天气 股价等等 排序问题 推荐 点击率排序 生成问题 图像
  • 完全卸载Android Studio(卸载得干干净净)

    步骤其实很简单 一共三步 但是每一步都需要完成 步骤如下 打开控制面板或腾讯软件管家等执行常规的卸载操作 找到SDK的安装目录手动删除SDK 进入 C Users lt 你的用户名下 gt 目录下 手动删除 android AndroidS
  • github 创建分支,本地代码上传github 服务器上

    git分布式版本控制系统 我第一个接触的版本控制系统是svn 当时觉得版本控制就是这样 直到我遇到了git git是分布式版本控制系统 合适分布式开发 强调个体 速度快 灵活 代码冲突了也比较好解决 最让我喜欢的还是git的分支切换 在gi
  • Python学习.第五天.列表

    Python学习 第五天 列表 前言 一 列表的创建与删除 二 列表的查询操作 1 index 如果查询时列表中存在n个相同元素 只返回元素中的第一个元素的索引 2 获取列表中的单个元素 3 获取列表中的多个元素 4 判断指定元素在列表中是
  • 目标检测之EfficientNet

    本文参考以下链接 如有侵权 联系删除 参考链接 论文 EfficientNet Rethinking Model Scaling for Convolutional Neural Networks EfficientNet Rethinki
  • 获取assert目录下文件名及读取

    从assert文件下获取文件名字 String fl1 getAssets list 第一层 得到数据 images hello txt String fl1 getAssets list 第一层 第二层 得到数据 helloworld t
  • IDEA+MAVEN 打jar包

    目录 一 分类 二 胖包 三 瘦包 一 分类 jar包是分为胖包和瘦包 何为胖包 何为瘦包 首先胖包指的是带依赖的jar包 瘦包就是没有依赖的jar包 二 胖包 1 在pom xml添加如下Maven插件
  • el-select 结合 el-checkBox 实现下拉全选+多选功能

    实现效果如图所示 具体代码如下
  • RabbitMQ重复消费

    造成重复消费的原因 MQ向消费者推送message 消费者向MQ返回ack 告知所推送的消息消费成功 但是由于网络波动等原因 可能造成消费者向MQ返回的ack丢失 MQ长时间 一分钟 收不到ack 于是会向消费者再次推送该条message
  • 每日一题(day1)

    题目链接 方法一 使用栈进行中序遍历 class Solution public int kthSmallest TreeNode root int k stack
  • 决策树算法处理分类及回归问题的原理及python代码实现

    1 决策树原理介绍 通俗的理解 决策树就是对样本集根据某一个维度d和某一个阈值v进行二分 得到二叉树 即为决策树 通过样本训练计算出维度d和阈值v 即可对预测数据进行分类 如果对二叉树的各子节点value值求平均 将平均值赋予待分类样本 即