当前位置: 首页 > news >正文

Python实现决策树算法:完整源码逐行解析

决策树是一种常用的机器学习算法,它可以用来解决分类和回归问题。决策树的优点是易于理解和解释,可以处理数值和类别数据,可以处理缺失值和异常值,可以进行特征选择和剪枝等操作。决策树的缺点是容易过拟合,对噪声和不平衡数据敏感,可能不稳定等。

在这篇文章中,将介绍如何用 Python 实现决策树算法,包括以下几个步骤:

目录

一、导入所需的库和数据集

二、定义决策树的节点类和树类

三、定义计算信息增益的函数

四、定义生成决策树的函数

五、定义预测新数据的函数

六、测试和评估决策树的性能


一、导入所需的库和数据集

        首先,我们需要导入一些常用的库,如 numpy, pandas, matplotlib 等,以及 sklearn 中的一些工具,如 train_test_split, accuracy_score 等。我们也需要导入一个用于测试的数据集,这里我们使用 sklearn 中自带的鸢尾花数据集(iris),它包含了 150 个样本,每个样本有 4 个特征(花萼长度、花萼宽度、花瓣长度、花瓣宽度)和 1 个类别(setosa, versicolor, virginica)。我们可以用以下代码来实现:

# 导入所需的库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt# 导入 sklearn 中的工具
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score# 导入鸢尾花数据集
iris = load_iris()
X = iris.data # 特征矩阵
y = iris.target # 类别向量
feature_names = iris.feature_names # 特征名称
class_names = iris.target_names # 类别名称# 查看数据集的基本信息
print("特征矩阵的形状:", X.shape)
print("类别向量的形状:", y.shape)
print("特征名称:", feature_names)
print("类别名称:", class_names)# 将数据集划分为训练集和测试集,比例为 7:3
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)# 查看训练集和测试集的大小
print("训练集的大小:", X_train.shape[0])
print("测试集的大小:", X_test.shape[0])

        运行上述代码,我们可以得到以下输出:

特征矩阵的形状: (150, 4)
类别向量的形状: (150,)
特征名称: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
类别名称: ['setosa' 'versicolor' 'virginica']
训练集的大小: 105
测试集的大小: 45

二、定义决策树的节点类和树类

        接下来,我们需要定义一个表示决策树节点的类 Node 和一个表示决策树本身的类 Tree。节点类的属性包括:

  • feature:节点的划分特征的索引,如果是叶子节点,则为 None
  • value:节点的划分特征的值,如果是叶子节点,则为 None
  • label:节点的类别标签,如果是叶子节点,则为该节点所属的类别,如果是非叶子节点,则为该节点所包含的样本中最多的类别
  • left:节点的左子树,如果没有,则为 None
  • right:节点的右子树,如果没有,则为 None

树类的属性包括:

  • root:树的根节点,初始为 None
  • max_depth:树的最大深度,用于控制过拟合,初始为 None
  • min_samples_split:树的最小分裂样本数,用于控制过拟合,初始为 2

        我们可以用以下代码来实现:

# 定义决策树节点类
class Node:def __init__(self, feature=None, value=None, label=None, left=None, right=None):self.feature = feature # 节点的划分特征的索引self.value = value # 节点的划分特征的值self.label = label # 节点的类别标签self.left = left # 节点的左子树self.right = right # 节点的右子树# 定义决策树类
class Tree:def __init__(self, max_depth=None, min_samples_split=2):self.root = None # 树的根节点self.max_depth = max_depth # 树的最大深度self.min_samples_split = min_samples_split # 树的最小分裂样本数

三、定义计算信息增益的函数

        为了生成决策树,我们需要选择一个合适的划分特征和划分值,使得划分后的子集尽可能地纯净。为了衡量纯净度,我们可以使用信息增益(information gain)作为评价指标。信息增益表示划分前后信息熵(information entropy)的减少量,信息熵表示数据集中不确定性或混乱程度的度量。信息增益越大,说明划分后数据集越纯净。

        我们可以用以下公式来计算信息熵和信息增益:

其中,

  • D 表示数据集
  • y 表示类别集合
  • pk​ 表示第 k 个类别在数据集中出现的概率
  • A 表示划分特征
  • V 表示划分特征取值的个数
  • Dv 表示划分特征取第 v 个值时对应的数据子集

        我们可以用以下代码来实现:

# 定义计算信息熵的函数
def entropy(y):n = len(y) # 数据集大小labels_count = {} # 统计不同类别出现的次数for label in y:if label not in labels_count:labels_count[label] = 0labels_count[label] += 1ent = 0.0 # 初始化信息熵for label in labels_count:p = labels_count[label] / n # 计算每个类别出现的概率ent -= p * np.log2(p) # 累加信息熵return ent# 定义计算信息增益的函数
def info_gain(X, y, feature, value):n = len(y) # 数据集大小# 根据特征和值划分数据X_left = X[X[:, feature] <= value] # 左子集,特征值小于等于划分值的样本y_left = y[X[:, feature] <= value] # 左子集对应的类别X_right = X[X[:, feature] > value] # 右子集,特征值大于划分值的样本y_right = y[X[:, feature] > value] # 右子集对应的类别# 计算划分前后的信息熵和信息增益ent_before = entropy(y) # 划分前的信息熵ent_left = entropy(y_left) # 左子集的信息熵ent_right = entropy(y_right) # 右子集的信息熵ent_after = len(y_left) / n * ent_left + len(y_right) / n * ent_right # 划分后的信息熵,加权平均gain = ent_before - ent_after # 信息增益return gain

四、定义生成决策树的函数

        接下来,我们需要定义一个生成决策树的函数,它的输入是训练数据和当前深度,它的输出是一个决策树节点。这个函数的主要步骤如下:

  • 如果当前数据集为空,或者当前深度达到最大深度,或者当前数据集中所有样本属于同一类别,或者当前数据集中所有样本在所有特征上取值相同,或者当前数据集大小小于最小分裂样本数,则返回一个叶子节点,其类别标签为当前数据集中最多的类别。
  • 否则,遍历所有特征和所有可能的划分值,计算每种划分方式的信息增益,并选择信息增益最大的特征和值作为划分依据。
  • 根据选择的特征和值,将当前数据集划分为左右两个子集,并递归地生成左右两个子树。
  • 返回一个非叶子节点,其划分特征和值为选择的特征和值,其左右子树为生成的左右子树。

        我们可以用以下代码来实现:

# 定义生成决策树的函数
def build_tree(X, y, depth=0):# 如果满足终止条件,则返回一个叶子节点if len(X) == 0 or depth == max_depth or len(np.unique(y)) == 1 or np.all(X == X[0]) or len(X) < min_samples_split:label = np.argmax(np.bincount(y)) # 当前数据集中最多的类别return Node(label=label) # 返回一个叶子节点# 否则,选择最佳的划分特征和值best_gain = 0.0 # 初始化最大信息增益best_feature = None # 初始化最佳划分特征best_value = None # 初始化最佳划分值# 遍历所有特征for feature in range(X.shape[1]):# 遍历所有可能的划分值,这里我们使用特征的中位数作为候选值value = np.median(X[:, feature])# 计算当前特征和值的信息增益gain = info_gain(X, y, feature, value)# 如果当前信息增益大于最大信息增益,则更新最佳划分特征和值if gain > best_gain:best_gain = gainbest_feature = featurebest_value = value# 根据最佳划分特征和值,划分数据集为左右两个子集X_left = X[X[:, best_feature] <= best_value] # 左子集,特征值小于等于划分值的样本y_left = y[X[:, best_feature] <= best_value] # 左子集对应的类别X_right = X[X[:, best_feature] > best_value] # 右子集,特征值大于划分值的样本y_right = y[X[:, best_feature] > best_value] # 右子集对应的类别# 递归地生成左右两个子树left = build_tree(X_left, y_left, depth + 1) # 左子树,深度加一right = build_tree(X_right, y_right, depth + 1) # 右子树,深度加一# 返回一个非叶子节点,其划分特征和值为最佳划分特征和值,其左右子树为生成的左右子树return Node(feature=best_feature, value=best_value, left=left, right=right)

        这样,我们就完成了决策树的生成过程。我们可以用以下代码来调用这个函数,并将生成的决策树赋给树类的根节点属性:

# 创建一个决策树对象
tree = Tree(max_depth=3) # 设置最大深度为 3# 用训练数据生成决策树,并将其赋给根节点属性
tree.root = build_tree(X_train, y_train)

五、定义预测新数据的函数

        接下来,我们需要定义一个预测新数据的函数,它的输入是一个新的样本和一个决策树节点,它的输出是一个预测的类别标签。这个函数的主要步骤如下:

  • 如果当前节点是叶子节点,则返回其类别标签。
  • 否则,根据当前节点的划分特征和值,将新样本划分到左右两个子树中的一个,并递归地在该子树上进行预测。
  • 返回预测结果。

我们可以用以下代码来实现:

# 定义预测新数据的函数
def predict(x, node):# 如果当前节点是叶子节点,则返回其类别标签if node.feature is None:return node.label# 否则,根据当前节点的划分特征和值,将新样本划分到左右两个子树中的一个,并递归地在该子树上进行预测if x[node.feature] <= node.value: # 如果新样本在当前节点划分特征上的取值小于等于划分值,则进入左子树return predict(x, node.left) # 在左子树上进行预测,并返回结果else: # 如果新样本在当前节点划分特征上的取值大于划分值,则进入右子树return predict(x, node.right) # 在右子树上进行预测,并返回结果

六、测试和评估决策树的性能

        这样,我们就完成了决策树的预测过程。我们可以用以下代码来调用这个函数,并对测试数据进行预测,并计算预测的准确率:

# 创建一个空的列表,用于存储预测结果
y_pred = []# 遍历测试数据,对每个样本进行预测,并将结果添加到列表中
for x in X_test:y_pred.append(predict(x, tree.root))# 将列表转换为 numpy 数组,方便计算
y_pred = np.array(y_pred)# 计算并打印预测的准确率
acc = accuracy_score(y_test, y_pred)
print("预测的准确率为:", acc)

        运行上述代码,我们可以得到以下输出:

预测的准确率为: 0.9777777777777777

        可以看到,用 Python 实现的决策树算法在鸢尾花数据集上达到了接近 98% 的准确率,这说明我们的算法是有效和可靠的。当然,决策树算法还有很多其他的细节和优化,比如如何选择最佳的划分值,如何处理数值和类别特征,如何进行剪枝和正则化等。

相关文章:

Python实现决策树算法:完整源码逐行解析

决策树是一种常用的机器学习算法&#xff0c;它可以用来解决分类和回归问题。决策树的优点是易于理解和解释&#xff0c;可以处理数值和类别数据&#xff0c;可以处理缺失值和异常值&#xff0c;可以进行特征选择和剪枝等操作。决策树的缺点是容易过拟合&#xff0c;对噪声和不…...

Linux文本三剑客---grep、sed、awk

目录标题 1、grep1.1 命令格式1.2命令功能1.3命令参数1.4grep实战演练 2、sed2.1 认识sed2.2命令格式2.3常用选项options2.4地址定界2.5 编辑命令command2.6用法演示2.6.1常用选项options演示2.6.2地址界定演示2.6.3编辑命令command演示 3、awk3.1认识awk3.2常用命令选项3.3awk…...

局域网VoIP网络电话测试

0. 环境 ubuntu18或者ubuntu22 - SIP服务器 win10 - SIP客户端1 ubuntu18 - SIP客户端2 1. SIP服务器搭建asterisk 1.0 环境 虚拟机ubuntu18 或者ubuntu22 1.1 直接安装 sudo apt-get install asterisk 1.2 配置用户信息 分为两个部分&#xff0c;第一部分是修改genera…...

el-table 去掉边框(修改颜色)

原始&#xff1a; 去掉表格的border属性&#xff0c;每一行下面还会有一条线&#xff0c;并且不能再拖拽表头 为了满足在隐藏表格边框的情况下还能拖动表头&#xff0c;修改相关css即可&#xff0c;如下代码 <style lang"less"> .table {//避免单元格之间出现白…...

redis与MongoDB的区别

1.Redis与MongoDB的概念 1.1 MongoDB MongoDB 是由C语言编写的&#xff0c;是一个基于分布式文件存储的开源数据库系统。 在高负载的情况下&#xff0c;添加更多的节点&#xff0c;可以保证服务器性能。 MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB …...

CSS设置高度

要设置 article.content 的恰当高度&#xff0c;您可以使用 CSS 来控制元素的外观。有几种方法可以设置元素的高度&#xff0c;具体取决于你的需求和布局。 以下是几种常见的方法&#xff1a; 1. 固定高度&#xff1a;你可以直接为 article.content 设置一个固定的高度值&…...

开源免费用|Apache Doris 2.0 推出跨集群数据复制功能

随着企业业务的发展&#xff0c;系统架构趋于复杂、数据规模不断增大&#xff0c;数据分布存储在不同的地域、数据中心或云平台上的现象越发普遍&#xff0c;如何保证数据的可靠性和在线服务的连续性成为人们关注的重点。在此基础上&#xff0c;跨集群复制&#xff08;Cross-Cl…...

【docker】docker-compose服务编排

目录 一、服务编排概念二、docker compose2.1 定义2.2 使用步骤2.3 docker-compose安装2.4 docker-compose卸载 三、编排示例 一、服务编排概念 1.微服务架构的应用系统中一般包含若干个微服务&#xff0c;每个微服务一般都会部署多个实例&#xff0c;如果每个微服务都要手动启…...

EdgeBox_tx1_A200 PyTorch v1.9.0 环境部署

大家好&#xff0c;我是虎哥&#xff0c;今天远程帮助几个小伙伴在A200 控制器上安装PyTorch v1.9.0 torchvision v0.10.0&#xff0c;中间也是经历了很多波折&#xff0c;当然&#xff0c;大部分是网络问题和版本适配问题&#xff0c;所以完事后&#xff0c;将自己完整可用的过…...

【雕爷学编程】MicroPython动手做(33)——物联网之天气预报

天气&#xff08;自然现象&#xff09; 是指某一个地区距离地表较近的大气层在短时间内的具体状态。而天气现象则是指发生在大气中的各种自然现象&#xff0c;即某瞬时内大气中各种气象要素&#xff08;如气温、气压、湿度、风、云、雾、雨、闪、雪、霜、雷、雹、霾等&#xff…...

分库分表之基于Shardingjdbc+docker+mysql主从架构实现读写分离 (三)

本篇主要说明&#xff1a; 1. 因为这个mysql版本是8.0&#xff0c;所以当其中一台mysql节点挂掉之后&#xff0c;主从同步&#xff0c;甚至双向数据同步都失效了&#xff0c;所以本篇主要记录下当其中的节点挂掉之后如何再次生效。另外推荐大家使用mysql5.7的版本&#xff0c;这…...

探秘企业DevOps一体化平台建设终极形态丨IDCF

笔者从事为企业提供研发效能改进解决方案相关工作十几年&#xff0c;为国内上百家企业提供过DevOps咨询及解决方案落地解决方案&#xff0c;涉及行业包括&#xff1a;金融、通信、制造、互联网、快销等多种行业。 DevOps的核心是研发效能改进&#xff0c;效能的提升离不开强大…...

百度智能创做AI平台

家人们好&#xff0c;在数字化时代&#xff0c;人工智能正引领着一场前所未有的创新浪潮。今天&#xff0c;我们将为大家介绍百度智能创做AI平台&#xff0c;这个为创意赋能、助力创作者的强大工具。无论你是创意工作者、内容创作者&#xff0c;还是想要释放内心创造力的个人&a…...

Python 开发工具 Pycharm —— 使用技巧Lv.1

Basic code completion Ctrl空格 is available in the search field when you search for text in the current file CtrlF, so there is no need to type the entire string 基本代码完成Ctrl 空格可在搜索领域当你搜索文本在当前文件Ctrl F,所以没有必要整个字符串类型 To m…...

zookeeper --- 高级篇

一、zookeeper 事件监听机制 1.1、watcher概念 zookeeper提供了数据的发布/订阅功能&#xff0c;多个订阅者可同时监听某一特定主题对象&#xff0c;当该主题对象的自身状态发生变化时(例如节点内容改变、节点下的子节点列表改变等)&#xff0c;会实时、主动通知所有订阅者 …...

TypeScript【enum 枚举】

导语 在 TypeScript 中&#xff0c;新增了很多具有特性的一些数据类型处理方法&#xff0c;enum 【枚举】就是其中&#xff0c;很具有代表性的一种&#xff0c;所以本章节就来聊聊 在 TypeScript 中如何去运用 enum 【枚举】。 枚举的概念&#xff1a; 枚举&#xff08;Enum&am…...

SpringBoot项目增加logback日志文件

一、简介 在开发和调试过程中&#xff0c;日志是一项非常重要的工具。它不仅可以帮助我们快速定位和解决问题&#xff0c;还可以记录和监控系统的运行状态。Spring Boot默认提供了一套简单易用且功能强大的日志框架logback&#xff0c;本文将介绍如何在Spring Boot项目中配置和…...

复习之selinux的管理

一、什么是selinux? SELinux&#xff0c;Security Enhanced Linux 的缩写&#xff0c;也就是安全强化的 Linux&#xff0c;是由美国国家安全局&#xff08;NSA&#xff09;联合其他安全机构&#xff08;比如 SCC 公司&#xff09;共同开发的&#xff0c;旨在增强传统 Linux 操…...

无涯教程-Lua - 文件I/O

I/O库用于在Lua中读取和处理文件。 Lua中有两种文件操作&#xff0c;即隐式(Implicit)和显式(Explicit)操作。 对于以下示例&#xff0c;无涯教程将使用例文件test.lua&#xff0c;如下所示。 -- sample test.lua -- sample2 test.lua 一个简单的文件打开操作使用以下语句。…...

java+ssm民宿酒店客房推荐预订系统_2k78b--论文

摘 要 互联网日益成熟&#xff0c;走进千家万户&#xff0c;改变多个行业传统的工作方式。民宿推荐管理以用户需求为基础&#xff0c;借由发展迅猛的互联网平台实现民宿推荐管理的信息化&#xff0c;简化旧时民宿推荐管理所需的纸质记录这一繁杂过程&#xff0c;从而大幅提高民…...

Docker实战-关于Docker镜像的相关操作(一)

导语   镜像&#xff0c;Docker中三大核心概念之一&#xff0c;并且在运行Docker容器之前需要本地存储对应的镜像。那么下面我们就来介绍一下在Docker中如何使用镜像。 如何获取镜像&#xff1f; 镜像作为容器运行的前提条件&#xff0c;在Docker Hub上提供了各种各样的开放的…...

Jenkins Gerrit Trigger实践

1.创建Gerrit Trigger 2.jenkins master节点生成gerrit用户的密钥 这里的用户名得写登录gerrit后个人信息中的 Username 3.gerrit 配置刚刚jenkins生成密钥的公钥 4.gerrit 用户加入群组 不加这个群组&#xff0c;下一步测试就会报错“User aeshare has no capability conn…...

Xcode protobuf2.5添加arm64编译器补丁生成静态库

项目需求&#xff0c;protobuf源码编成静态库使用 但是&#xff0c;github上的protobuf源码没有对应arm64的编译器定义&#xff0c;编译出来的静态库使用时报错。 下面的连接是arm64编译器代码补丁包&#xff0c;把编译器代码放到src/google/protobuf/stubs/atomicops_intern…...

计算机毕设 深度学习疫情社交安全距离检测算法 - python opencv cnn

文章目录 0 前言1 课题背景2 实现效果3 相关技术3.1 YOLOV43.2 基于 DeepSort 算法的行人跟踪 4 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两…...

四数之和——力扣18

文章目录 题目描述双指针法题目描述 双指针法 class Solution {public:vector<vector<int>>...

Serializable 和 Externalizable区别?

Serializable接口 java.io.Serializable 接口没有方法或字段&#xff0c;仅用于标识可序列化的语义。 public interface Serializable { }可序列化类的所有子类型本身都是可序列化的。在进行序列化操作时&#xff0c;会判断要被序列化的类是否是Enum、Array和 Serializable类…...

2023 电赛 E 题 K210 方案--K210实现矩形识别

相关库介绍 sensor&#xff08;摄像头&#xff09; sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.skip_frames(10) reset()&#xff1a;重置并初始化单目摄像头 set_pixformat()&#xff1a;设置摄像头输出格式&#xff0c…...

【雕爷学编程】MicroPython动手做(29)——物联网之SIoT 2

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…...

chapter13:springboot与任务

Spring Boot与任务视频 1. 异步任务 使用注解 Async 开启一个异步线程任务&#xff0c; 需要在主启动类上添加注解EnableAsync开启异步配置&#xff1b; Service public class AsyncService {Asyncpublic void hello() {try {Thread.sleep(3000);} catch (InterruptedExcept…...

(十一)大数据实战——hadoop高可用之HDFS手动模式高可用

前言 本节内容我们介绍一下hadoop在手动模式下如何实现HDFS的高可用&#xff0c;HDFS的高可用功能是通过配置多个 NameNodes(Active/Standby)实现在集群中对 NameNode 的热备来解决上述问题。如果出现故障&#xff0c;如机器崩溃或机器需要升级维护&#xff0c;这时可通过此种…...