机器学习:回归决策树(Python)

一、平方误差的计算

square_error_utils.py

import numpy as npclass SquareErrorUtils:"""平方误差最小化准则,选择其中最优的一个作为切分点对特征属性进行分箱处理"""@staticmethoddef _set_sample_weight(sample_weight, n_samples):"""扩展到集成学习,此处为样本权重的设置:param sample_weight: 各样本的权重:param n_samples: 样本量:return:"""if sample_weight is None:sample_weight = np.asarray([1.0] * n_samples)return sample_weight@staticmethoddef square_error(y, sample_weight):"""平方误差:param y: 当前划分区域的目标值集合:param sample_weight: 当前样本的权重:return:"""y = np.asarray(y)return np.sum((y - y.mean()) ** 2 * sample_weight)def cond_square_error(self, x, y, sample_weight):"""计算根据某个特征x划分的区域中y的误差值:param x: 某个特征划分区域所包含的样本:param y: x对应的目标值:param sample_weight: 当前x的权重:return:"""x, y = np.asarray(x), np.asarray(y)error = 0.0for x_val in set(x):x_idx = np.where(x == x_val)  # 按区域计算误差new_y = y[x_idx]  # 对应区域的目标值new_sample_weight = sample_weight[x_idx]error += self.square_error(new_y, new_sample_weight)return errordef square_error_gain(self, x, y, sample_weight=None):"""平方误差带来的增益值:param x: 某个特征变量:param y: 对应的目标值:param sample_weight: 样本权重:return:"""sample_weight = self._set_sample_weight(sample_weight, len(x))return self.square_error(y, sample_weight) - self.cond_square_error(x, y, sample_weight)

 二、树的结点信息封装


class TreeNode_R:"""决策树回归算法,树的结点信息封装,实体类:setXXX()、getXXX()"""def __init__(self, feature_idx: int = None, feature_val=None, y_hat=None, square_error: float = None,criterion_val=None, n_samples: int = None, left_child_Node=None, right_child_Node=None):"""决策树结点信息封装:param feature_idx: 特征索引,如果指定特征属性的名称,可以按照索引取值:param feature_val: 特征取值:param square_error: 划分结点的标准:当前结点的平方误差:param n_samples: 当前结点所包含的样本量:param y_hat: 当前结点的预测值:Ci:param left_child_Node: 左子树:param right_child_Node: 右子树"""self.feature_idx = feature_idxself.feature_val = feature_valself.criterion_val = criterion_valself.square_error = square_errorself.n_samples = n_samplesself.y_hat = y_hatself.left_child_Node = left_child_Node  # 递归self.right_child_Node = right_child_Node  # 递归def level_order(self):"""按层次遍历树...:return:"""pass# def get_feature_idx(self):#     return self.get_feature_idx()## def set_feature_idx(self, feature_idx):#     self.feature_idx = feature_idx

三、回归决策树CART算法实现

import numpy as np
from utils.square_error_utils import SquareErrorUtils
from utils.tree_node_R import TreeNode_R
from utils.data_bin_wrapper import DataBinsWrapperclass DecisionTreeRegression:"""回归决策树CART算法实现:按照二叉树构造1. 划分标准:平方误差最小化2. 创建决策树fit(),递归算法实现,注意出口条件3. 预测predict_proba()、predict() --> 对树的搜索4. 数据的预处理操作,尤其是连续数据的离散化,分箱5. 剪枝处理"""def __init__(self, criterion="mse", max_depth=None, min_sample_split=2, min_sample_leaf=1,min_target_std=1e-3, min_impurity_decrease=0, max_bins=10):self.utils = SquareErrorUtils()  # 结点划分类self.criterion = criterion  # 结点的划分标准if criterion.lower() == "mse":self.criterion_func = self.utils.square_error_gain  # 平方误差增益else:raise ValueError("参数criterion仅限mse...")self.min_target_std = min_target_std  # 最小的样本目标值方差,小于阈值不划分self.max_depth = max_depth  # 树的最大深度,不传参,则一直划分下去self.min_sample_split = min_sample_split  # 最小的划分结点的样本量,小于则不划分self.min_sample_leaf = min_sample_leaf  # 叶子结点所包含的最小样本量,剩余的样本小于这个值,标记叶子结点self.min_impurity_decrease = min_impurity_decrease  # 最小结点不纯度减少值,小于这个值,不足以划分self.max_bins = max_bins  # 连续数据的分箱数,越大,则划分越细self.root_node: TreeNode_R() = None  # 回归决策树的根节点self.dbw = DataBinsWrapper(max_bins=max_bins)  # 连续数据离散化对象self.dbw_XrangeMap = {}  # 存储训练样本连续特征分箱的端点def fit(self, x_train, y_train, sample_weight=None):"""回归决策树的创建,递归操作前的必要信息处理(分箱):param x_train: 训练样本:ndarray,n * k:param y_train: 目标集:ndarray,(n, ):param sample_weight: 各样本的权重,(n, ):return:"""x_train, y_train = np.asarray(x_train), np.asarray(y_train)self.class_values = np.unique(y_train)  # 样本的类别取值n_samples, n_features = x_train.shape  # 训练样本的样本量和特征属性数目if sample_weight is None:sample_weight = np.asarray([1.0] * n_samples)self.root_node = TreeNode_R()  # 创建一个空树self.dbw.fit(x_train)x_train = self.dbw.transform(x_train)self._build_tree(1, self.root_node, x_train, y_train, sample_weight)def _build_tree(self, cur_depth, cur_node: TreeNode_R, x_train, y_train, sample_weight):"""递归创建回归决策树算法,核心算法。按先序(中序、后序)创建的:param cur_depth: 递归划分后的树的深度:param cur_node: 递归划分后的当前根结点:param x_train: 递归划分后的训练样本:param y_train: 递归划分后的目标集合:param sample_weight: 递归划分后的各样本权重:return:"""n_samples, n_features = x_train.shape  # 当前样本子集中的样本量和特征属性数目# 计算当前数结点的预测值,即加权平均值,cur_node.y_hat = np.dot(sample_weight / np.sum(sample_weight), y_train)cur_node.n_samples = n_samples# 递归出口判断cur_node.square_error = ((y_train - y_train.mean()) ** 2).sum()# 所有的样本目标值较为集中,样本方差非常小,不足以划分if cur_node.square_error <= self.min_target_std:# 如果为0,则表示当前样本集合为空,递归出口3returnif n_samples < self.min_sample_split:  # 当前结点所包含的样本量不足以划分returnif self.max_depth is not None and cur_depth > self.max_depth:  # 树的深度达到最大深度return# 划分标准,选择最佳的划分特征及其取值best_idx, best_val, best_criterion_val = None, None, 0.0for k in range(n_features):  # 对当前样本集合中每个特征计算划分标准for f_val in sorted(np.unique(x_train[:, k])):  # 当前特征的不同取值region_x = (x_train[:, k] <= f_val).astype(int)  # 是当前取值f_val就是1,否则就是0criterion_val = self.criterion_func(region_x, y_train, sample_weight)if criterion_val > best_criterion_val:best_criterion_val = criterion_val  # 最佳的划分标准值best_idx, best_val = k, f_val  # 当前最佳特征索引以及取值# 递归出口的判断if best_idx is None:  # 当前属性为空,或者所有样本在所有属性上取值相同,无法划分returnif best_criterion_val <= self.min_impurity_decrease:  # 小于最小不纯度阈值,不划分returncur_node.criterion_val = best_criterion_valcur_node.feature_idx = best_idxcur_node.feature_val = best_val# print("当前划分的特征索引:", best_idx, "取值:", best_val, "最佳标准值:", best_criterion_val)# print("当前结点的类别分布:", target_dist)# 创建左子树,并递归创建以当前结点为子树根节点的左子树left_idx = np.where(x_train[:, best_idx] <= best_val)  # 左子树所包含的样本子集索引if len(left_idx) >= self.min_sample_leaf:  # 小于叶子结点所包含的最少样本量,则标记为叶子结点left_child_node = TreeNode_R()  # 创建左子树空结点# 以当前结点为子树根结点,递归创建cur_node.left_child_Node = left_child_nodeself._build_tree(cur_depth + 1, left_child_node, x_train[left_idx],y_train[left_idx], sample_weight[left_idx])right_idx = np.where(x_train[:, best_idx] > best_val)  # 右子树所包含的样本子集索引if len(right_idx) >= self.min_sample_leaf:  # 小于叶子结点所包含的最少样本量,则标记为叶子结点right_child_node = TreeNode_R()  # 创建右子树空结点# 以当前结点为子树根结点,递归创建cur_node.right_child_Node = right_child_nodeself._build_tree(cur_depth + 1, right_child_node, x_train[right_idx],y_train[right_idx], sample_weight[right_idx])def _search_tree_predict(self, cur_node: TreeNode_R, x_test):"""根据测试样本从根结点到叶子结点搜索路径,判定所属区域(叶子结点)搜索:按照后续遍历:param x_test: 单个测试样本:return:"""if cur_node.left_child_Node and x_test[cur_node.feature_idx] <= cur_node.feature_val:return self._search_tree_predict(cur_node.left_child_Node, x_test)elif cur_node.right_child_Node and x_test[cur_node.feature_idx] > cur_node.feature_val:return self._search_tree_predict(cur_node.right_child_Node, x_test)else:# 叶子结点,类别,包含有类别分布return cur_node.y_hatdef predict(self, x_test):"""预测测试样本x_test的预测值:param x_test: 测试样本ndarray、numpy数值运算:return:"""x_test = np.asarray(x_test)  # 避免传递DataFrame、list...if self.dbw.XrangeMap is None:raise ValueError("请先进行回归决策树的创建,然后预测...")x_test = self.dbw.transform(x_test)y_test_pred = []  # 用于存储测试样本的预测值for i in range(x_test.shape[0]):y_test_pred.append(self._search_tree_predict(self.root_node, x_test[i]))return np.asarray(y_test_pred)@staticmethoddef cal_mse_r2(y_test, y_pred):"""模型预测的均方误差MSE和判决系数R2:param y_test: 测试样本的真值:param y_pred: 测试样本的预测值:return:"""y_test, y_pred = y_test.reshape(-1), y_pred.reshape(-1)mse = ((y_pred - y_test) ** 2).mean()  # 均方误差r2 = 1 - ((y_pred - y_test) ** 2).sum() / ((y_test - y_test.mean()) ** 2).sum()return mse, r2def _prune_node(self, cur_node: TreeNode_R, alpha):"""递归剪枝,针对决策树中的内部结点,自底向上,逐个考察方法:后序遍历:param cur_node: 当前递归的决策树的内部结点:param alpha: 剪枝阈值:return:"""# 若左子树存在,递归左子树进行剪枝if cur_node.left_child_Node:self._prune_node(cur_node.left_child_Node, alpha)# 若右子树存在,递归右子树进行剪枝if cur_node.right_child_Node:self._prune_node(cur_node.right_child_Node, alpha)# 针对决策树的内部结点剪枝,非叶结点if cur_node.left_child_Node is not None or cur_node.right_child_Node is not None:for child_node in [cur_node.left_child_Node, cur_node.right_child_Node]:if child_node is None:# 可能存在左右子树之一为空的情况,当左右子树划分的样本子集数小于min_samples_leafcontinueif child_node.left_child_Node is not None or child_node.right_child_Node is not None:return# 计算剪枝前的损失值(平方误差),2表示当前结点包含两个叶子结点pre_prune_value = 2 * alphaif cur_node and cur_node.left_child_Node is not None:pre_prune_value += (0.0 if cur_node.left_child_Node.square_error is Noneelse cur_node.left_child_Node.square_error)if cur_node and cur_node.right_child_Node is not None:pre_prune_value += (0.0 if cur_node.right_child_Node.square_error is Noneelse cur_node.right_child_Node.square_error)# 计算剪枝后的损失值,当前结点即是叶子结点after_prune_value = alpha + cur_node.square_errorif after_prune_value <= pre_prune_value:  # 进行剪枝操作cur_node.left_child_Node = Nonecur_node.right_child_Node = Nonecur_node.feature_idx, cur_node.feature_val = None, Nonecur_node.square_error = Nonedef prune(self, alpha=0.01):"""决策树后剪枝算法(李航)C(T) + alpha * |T|:param alpha: 剪枝阈值,权衡模型对训练数据的拟合程度与模型的复杂度:return:"""self._prune_node(self.root_node, alpha)return self.root_node

 四、回归决策树算法的测试

test_decision_tree_R.py

import numpy as np
import matplotlib.pyplot as plt
from decision_tree_R import DecisionTreeRegression
from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressorobj_fun = lambda x: np.sin(x)
np.random.seed(0)
n = 100
x = np.linspace(0, 10, n)
target = obj_fun(x) + 0.3 * np.random.randn(n)
data = x[:, np.newaxis]  # 二维数组tree = DecisionTreeRegression(max_bins=50, max_depth=10)
tree.fit(data, target)
x_test = np.linspace(0, 10, 200)
y_test_pred = tree.predict(x_test[:, np.newaxis])
mse, r2 = tree.cal_mse_r2(obj_fun(x_test), y_test_pred)plt.figure(figsize=(14, 5))
plt.subplot(121)
plt.scatter(data, target, s=15, c="k", label="Raw Data")
plt.plot(x_test, y_test_pred, "r-", lw=1.5, label="Fit Model")
plt.xlabel("x", fontdict={"fontsize": 12, "color": "b"})
plt.ylabel("y", fontdict={"fontsize": 12, "color": "b"})
plt.grid(ls=":")
plt.legend(frameon=False)
plt.title("Regression Decision Tree(UnPrune) and MSE = %.5f R2 = %.5f" % (mse, r2))plt.subplot(122)
tree.prune(0.5)
y_test_pred = tree.predict(x_test[:, np.newaxis])
mse, r2 = tree.cal_mse_r2(obj_fun(x_test), y_test_pred)
plt.scatter(data, target, s=15, c="k", label="Raw Data")
plt.plot(x_test, y_test_pred, "r-", lw=1.5, label="Fit Model")
plt.xlabel("x", fontdict={"fontsize": 12, "color": "b"})
plt.ylabel("y", fontdict={"fontsize": 12, "color": "b"})
plt.grid(ls=":")
plt.legend(frameon=False)
plt.title("Regression Decision Tree(Prune) and MSE = %.5f R2 = %.5f" % (mse, r2))plt.show()

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

跳跃表的底层实现

跳跃表的底层是由 C 语言实现的&#xff0c;它的实现源码如下&#xff1a; typedef struct zskiplistNode {// 成员对象robj *obj;double score; // 分值struct zskiplistNode *backward; // 回退指针//层struct zskiplistLevel {// 前进指针struct zskiplistNode *forward;//…

缓存穿透、缓存击穿与缓存雪崩

缓存穿透、缓存击穿与缓存雪崩 1.本质区别 缓存穿透指的是数据库不存在数据&#xff0c;导致无法缓存&#xff0c;每次查询都查数据库&#xff0c;数据库压垮 缓存击穿指的是缓存键值对key过期了&#xff0c;key过期期间&#xff0c;大量请求访问&#xff0c;不经过缓存&…

USMART是什么?

一、USMART简介 USMART是一个串口调试组件&#xff0c;可以大大提高代码调试效率&#xff0c;为正点原子为STM32开发的类似linux中shell的调试工具。 一般开发者正常情况下&#xff0c;对单片机功能进行调试的过程大致为&#xff1a;下载——调试——修改——下载——调试——…

【精选】java初识多态 子类继承父类

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

Jumserver 安装

一、Jumserver 官网地址 Jumserver官网地址 二、Jumserver的基本概率 1、4a概率 首先&#xff0c;堡参机提供了运维安全审计的4A规范 Authentication: 身份鉴别&#xff0c;防止身份冒用和复用(开发10人&#xff0c;测试5人&#xff0c;运维2人&#xff09; Authorizatton:授…

【微机原理与单片机接口技术】MCS-51单片机的引脚功能介绍

前言 MCS-51是指由美国Intel公司生产的一系列单片机的总称。MCS-51系列单片机型号有很多&#xff0c;按功能分位基本型和增强型两大类&#xff0c;分别称为8051系列单片机和8052系列单片机&#xff0c;两者以芯片型号中的末位数字区分&#xff0c;1为基本型&#xff0c;2为增强…

如何看待频域与时域的仿真差别

从信号与系统理论中,可以知道,对于占空比为50%的周期信号,只含有奇次谐波,实际中,时钟信号并不是理想的占空比为50%的梯形波,因此,会同时含有奇偶次谐波,一个典型的案例,DDR仿真中,如果用模拟的理想激励源,如下图所示,可以发现,频谱中只会存在基频及其奇次谐波。 …

Android:Volley框架使用

3.15 Volley框架使用 Volley框架主要作为网络请求,图片加载工具。当应用数据量小、网络请求频繁,可以使用Volley框架。 框架Github地址:https://github.com/google/volley Volley框架的简单使用,创建项目Pro_VolleyDemo。将Github上下载Volley框架源代码,volley-master.zi…

C#,佩尔数(Pell Number)的算法与源代码

1 佩尔数&#xff08;Pell Number&#xff09; 佩尔数&#xff08;Pell Number&#xff09;是一个自古以来就知道的整数数列&#xff0c;由递推关系定义&#xff0c;与斐波那契数类似。佩尔数呈指数增长&#xff0c;增长速率与白银比的幂成正比。它出现在2的算术平方根的近似值…

Qt简易登录界面

代码&#xff1a; #include "mywidget.h" #include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent), ui(new Ui::MyWidget) {ui->setupUi(this);ui->background->setPixmap(QPixmap(":/qt picture/logo.png"))…

三极管从入门到精通

文章目录 摘要1 基础1.1 PN结1.2 三极管 2 三极管模拟电路知识2.1 I-V特性曲线2.2 极限参数解释2.3 基本共射极放大电路2.4 小信号模型2.5 用小信号模型分析基本共射极放大电路 3 三极管实际模拟电路应用图3.1 共射极放大电路3.1.1 基本共射极放大电路3.1.2 基极分压式射极偏置…

vue3 之 通用组件统一注册全局

components/index.js // 把components中的所组件都进行全局化注册 // 通过插件的方式 import ImageView from ./ImageView/index.vue import Sku from ./XtxSku/index.vue export const componentPlugin {install (app) {// app.component(组件名字&#xff0c;组件配置对象)…

REvil/Sodinokibi勒索病毒通用解密工具

前言 REvil/Sodinokibi勒索病毒相信关注我公众号的朋友&#xff0c;应该都不会陌生了&#xff0c;如果不清楚的可以去翻看之前的文章吧&#xff0c;如果你见过类似下面这样的勒索病毒攻击之后的电脑桌面&#xff0c;如下所示&#xff1a; 或者你见过这样的勒索提示界面&#x…

【跳槽须知】关于企业所签订的竞业协议你知道多少?

年后跳槽须知自己签订的合同中是否存在竞业协议&#xff0c;谨防协议造成经济损失 &#x1f413; 什么是竞业协议 竞业协议时用于保护自己的权益&#xff0c;在员工离职时决定是否启动的一种协议&#xff0c;避免一些掌握公司机密的一些重要岗位人才流入竞争对手的公司&#xf…

数字信号处理 试题 复盘解答(八)

数字信号处理 试题 复盘解答&#xff08;八&#xff09; ps:仅 用作复盘 和回顾知识点&#xff0c;如果有疑问或者错误请提出。 涉及年份 &#xff1a;19 - 21年 六、 个人感觉缺少条件 七、 使用双线性变换法对一个最小相位模拟滤波器进行数字化得到的数字滤波器一般来说不再…

GEE Colab——如何利用Matplotlib在colab中进行图形制作

在colab中绘制图表 笔记本的一个常见用途是使用图表进行数据可视化。Colaboratory 提供多种图表工具作为 Python 导入,让这一工作变得简单。 Matplotlib Matplotlib 是最常用的图表工具包,详情请查看其文档,并通过示例获得灵感。 线性图 线性图是一种常见的图表类型,用…

MySQL篇----第十六篇

系列文章目录 文章目录 系列文章目录前言一、数据库中的事务是什么?二、SQL 注入漏洞产生的原因?如何防止?三、为表中得字段选择合适得数据类型四、存储时期前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇…

IDEA-将压缩的一行代码恢复到原有格式

背景 有时需要将原来的一行代码恢复到未压缩前的格式&#xff0c;方便查看 示例&#xff1a; 通过IDEA自带的功能&#xff1a; 快捷键&#xff1a; MAC版&#xff1a;option command L 效果&#xff1a;

计算机网络基础 第一章——计算机网络概论 知识点

1.1计算机网络的形成与发展 1.计算机网络的特点 &#xff08;1&#xff09;计算机网络技术在现代社会发展中的作用 ●21世纪一个重要特征是:数字化、网络化与信息化&#xff0c;它的基础是支持全社会的、强大的计算机网络。 ●计算机网络是当今计算机学科中发展最为迅速的技…

vue.js基于springboot的实验室设备管理系统10345

(1)设备信息模块&#xff1a;记录设备的基本信息&#xff0c;如设备采购来源信息、设备需求量、当前数量、日期等。 (2) 用户模块&#xff1a;教师职工。实现对用户个人信息、消息管理和实验室设备的查询使用申请等。 (3) 管理员模块&#xff1a;实现对所有设备信息的增删改查&…