cart决策树Matlab实现,CART决策树的理解及其实现

article/2025/9/24 15:41:19

CART决策树介绍

使用CART(Classification and regression tree)算法构建的决策树是二叉树,它对特征进行二分,迭代生成决策树。

CART回归树

假设X与Y分别为输入和输出变量,并且Y是连续变量,给定训练数据集

$$D=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\}$$

考虑如何生成回归树。

一个回归树对应着输入空间(即特征空间)的一个划分以及在划分的单元上的输出值。假设已将输入空间划分为M个单元$R_1|R_2,...,R_M$,并且在每个单元$R_m$上有一个固定的输出值$c_m$,于是回归树模型可表示为

$$f(x)=\sum_{m=1}^Mc_mI(x\in R_m)\tag{1}$$

当输入空间的划分确定时,可以用平方误差$\sum_{x_i\in R_m}(y_i-f(x_i))^2$来表示回归树对于训练数据的预测误差,用平方误差最小的准则求解每个单元上的最优输出值。易知,单元$R_m$上的$c_m$的最优值$\hat{c_m}$是$R_m$上的所有输入实例$x_i$对应的输出$y_i$的均值,即

$$\hat{c_m}=ave(y_i|x_i\in R_m)\tag{2}$$

这里选择第j个遍历$x^{j}$和它的取值s,作为切分遍历和切分点,并定义两个区域(左右结点)

$$\begin{cases} R_1(j,s)=\{x|x^{j}\leq s\}\\ R_2(j,s)=\{x|x^{j}> s\} \end{cases} \tag{3}$$

然后寻找最优切分变量j个最优切分点s。具体地,求解

$$min_{j,s}[min_{c_1}\sum_{x_i\in R_1(j,s)}(y_i-c_1)^2+min_{c_2}\sum_{x_i\in R_2(j,s)}(y_i-c_2)^2]\tag{4}$$

对固定输入变量j可以找到最优切分点s

$$\begin{cases}\hat{c_1}=ave(y_i|x_j\in R_1(j,s))\\ \hat{c_2}=ave(y_i|x_i\in R_2(j, s))\end{cases} \tag{5}$$

遍历所有输入变量,找到最优的切分变量j,构成一对(j,s)。以此将输入空间划分为两个区域。接着,对每个区域重复上述划分过程,知道满足停止条件为止(可以是满足叶子结点个数或误差阈值等条件)。这样就生成一颗回归树。这样的树通常称为最小二乘回归树。

具体过程如下

输入:训练数据集D(N,J)

输出:回归树f(x)

选择最优切分变量(特征)和切分点遍历所有特征。对该特征,按照式(3)依次计算第j个特征下的每个取值对应的平方误差。选择最小的特征和特征切分点对。

使用上一步得到的最佳的特征和特征切分对数据集D进行切分,得到左子树(满足条件进入)和右子树(不满足条件进入)。

继续执行步骤1和2(生成子树),直至满足停止条件。

得到回归树。

这里举一个简单的例子,介绍一下连续变量如何切分(和C4.5的处理方式是一样的)。

下表是一个数据集,包含了一个特征x,x为连续变量。y为类别标签。现在利用这个数据集来构建一个CART回归树。

x

1

2

3

4

5

6

7

8

9

y

0.3

0.5

0.7

0.8

0.95

1.3

1.5

1.6

1.9

首先需要选择特征和特征切分点

特征x包含了9个元素,长度为9,这里x已经排序好了,直接以$\frac{x_i+x_{i+1}}{2},i\in \{1,2,..., 9\}$作为切分点(一种常用的切分方式)。

从第一个切分点开始,第一个切分点为$\frac{1 + 2}{2}=1.5$。小于1.5则归到$R_1$(左子树),大于1.5则归为$R_2$(右子树)。

根据式(3)可得,$R_1=\{1\}$,$R_1=\{2,3,4,5,6,7,8,9\}$,根据式(5)可得,$c_1=0.3$,$c_2=\frac{0.5+0.7+0.8+0.95+1.3+1.5+1.6+1.9}{8}$,所以根据式(4),第一个切分点对应平方误差为$0+0.21=0.21$。按照这种方式依次计算每个切分点对应的误差,选择具有最小误差的切分点。

CART分类树

CART分类树使用最小基尼指数(Gini)准则来选择特征,同时决定最优切分点。

基尼指数的定义如下

$$G(p)=\sum_{k=1}^Kp_k(1-p_k)=1-\sum_{k=1}^Kp_k^2\tag{6}$$

对于指定的数据集D,其基尼系数为:

$$G(D)=\sum_{k=1}^K\frac{|C_k|}{|D|}(1-\frac{|C_k|}{|D|})\tag{6}$$

$|C_k|$表示第k类的样本数目。

设特征A的取值将数据集D分成两部分$D_1$和$D_2$。在特征A的条件下,数据集D的基尼系数定义为:

$$G(D,A)=\sum_{k=1}^K\frac{|D_1|}{|D|}G(D_1)+\sum_{k=1}^K\frac{|D_2|}{|D|}G(D_2)$$

G(D)表示数据集D的不确定性,基尼指数越大,不确定性越大。这点和熵比较相似。

CART分类决策树和上一节中的ID3和C4.5构建决策树的差别不大,这里就不细说。下面直接给出CART分类树构建的代码。

代码实现

结点

class Node:

def __init__(self, val, tag=None):

"""

Params:

val: 特征名(内部节点)或类别标签(叶子节点)

tag: 切分点

left: 左子树

right: 左子树

"""

self.val = val

self.left = None

self.right = None

self.tag = tag

def __str__(self):

return f'val: {self.val}, tag: {self.tag}'

CART分类树

class CARTClassifier:

def __init__(self, thresh=1e-3, feat_names=None):

self.tree = None

self.feat_names = feat_names

self.thresh = thresh

def fit(self, x_train, y_train):

"""

构建决策树

"""

self.tree = self._build(x_train, y_train)

print('Finish train...')

def predict(self, x_test, y_test=None):

"""

预测

"""

if self.tree == None:

return

y_pred = []

for x in x_test:

y_pred.append(self._search(x))

y_pred = np.array(y_pred)

if y_test is not None:

self._score(y_test, y_pred)

return y_pred

def _search(self, x):

"""

根据特征取值进行搜索

"""

root = self.tree

tag = root.tag

while tag is not None:

idx = self.feat_names.index(root.val)

if isinstance(x[idx], str):

root = root.left if x[idx] == root.tag else root.right

else:

root = root.left if x[idx] < root.tag else root.right

tag = root.tag

return root.val

def _score(self, y_test, y_pred):

"""

计算预测得分(准确率)

"""

self.score = np.count_nonzero(y_test == y_pred) / len(y_test)

def _build(self, x, y):

"""

Params:

x(pandas.DataFrame): 特征features

y(pandas.DataFrame or numpy.array): 标签labels

"""

cks, cnts = np.unique(y, return_counts=True)

if len(cks) == 1:

return Node(cks[0])

if x.shape[0] == 0:

return None

self.feat_names = list(x.columns)

best_gini = float('inf')

best_split = None

best_feat = 0

# 特征选择

for i in range(x.shape[1]):

if x.iloc[:, i].dtypes != 'object':

gini, split = self.calc_cond_gini_continuous(x.iloc[:, i], y)

else:

gini, split = self.calc_cond_gini(x.iloc[:, i], y)

if gini < best_gini:

best_gini = gini

best_split = split

best_feat = i

if best_gini < self.thresh:

return Node(cks[cnts.argmax(0)])

tree = Node(self.feat_names[best_feat], best_split)

# 连续特征处理

if x.iloc[:, best_feat].dtypes != 'object':

fmask = x.iloc[:, best_feat] < best_split

bmask = x.iloc[:, best_feat] > best_split

# 离散特征处理

else:

fmask = x.iloc[:, best_feat] == best_split

bmask = x.iloc[:, best_feat] != best_split

tree.left = self._build(x[fmask], y[fmask])

tree.right = self._build(x[bmask], y[bmask])

return tree

# 计算基尼系数

def calc_gini(self, label):

gini = 0

for (ck, cnt) in zip(*np.unique(label, return_counts=True)):

prob_ck = cnt / len(label)

gini += prob_ck * (1 - prob_ck)

return gini

# 处理离散特征

def calc_cond_gini(self, feat, label):

cks = np.unique(feat)

best_gini = float('inf')

best_split = 0

for ck in cks:

fmask = feat == ck

bmask = feat != ck

cond_gini = sum(fmask) * self.calc_gini(label[fmask])/ len(label) + sum(bmask) * self.calc_gini(label[bmask])/ len(label)

if cond_gini < best_gini:

best_gini = cond_gini

best_split = ck

return best_gini, best_split

# 处理连续特征

def calc_cond_gini_continuous(self, feat, label):

# 对特征进行升序排序

sorted_feat = np.sort(feat, axis=0)

sorted_feat = np.unique(sorted_feat)

# 确定可能的划分点

split_pos = (sorted_feat[:-1] + sorted_feat[1:]) / 2

best_gini = float('inf')

best_split = 0

for pos in split_pos:

lmask = feat < pos

rmask = feat > pos

cond_gini = sum(lmask) * self.calc_gini(label[lmask])/ len(label) + sum(rmask) * self.calc_gini(label[rmask])/ len(label)

if cond_gini < best_gini:

best_gini = cond_gini

best_split = pos

return best_gini, best_split

def pruning(self, tree, x_test, y_test):

"""

后剪枝

根据测试集, 对创建好的决策树进行剪枝

"""

# TODO

pass

def preorder(self):

"""

决策树前序遍历

"""

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

tree = self.tree

self._preorder(tree)

def _preorder(self, tree):

if tree == None:

return

print(tree)

self._preorder(tree.left)

self._preorder(tree.right)

构建CART决策树并执行分类,这里还是以Iris数据集为例

# 读取数据

data = load_iris()

x, y = data['data'], data['target']

# 分割成训练集和测试集

x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=20190320, test_size=0.1)

x_train = pd.DataFrame(x_train, columns=data.feature_names, index=None)

# 构建决策树

tree = CARTClassifier()

tree.fit(x_train, y_train)

# CART决策树前序遍历

tree.preorder()

# 执行预测

y_pred = tree.predict(x_test, y_test)

print(tree.score)

代码实现结果

bVbELjb

总结

本节主要介绍了CART回归树和分类树的构建过程,决策树的剪枝之后再讨论吧,就这样吧。

Reference

李航《统计学习方法》


http://chatgpt.dhexx.cn/article/ParJ2L6n.shtml

相关文章

CART决策树算法Python实现 (人工智能导论作业)

文章目录 决策树的介绍CART决策树算法简介基尼指数 CART决策树生成算法及Python代码实现 决策树的介绍 决策树是以树的结构将决策或者分类过程展现出来&#xff0c;其目的是根据若干输入变量的值构造出一个相适应的模型&#xff0c;来预测输出变量的值。预测变量为离散型时&am…

CART树分类、回归、剪枝实现

决策树ID3&#xff0c;C4.5是多叉树&#xff0c;CART树是一个完全二叉树&#xff0c;CART树不仅能完成分类也能实现回归功能&#xff0c;所谓回归指的是目标是一个连续的数值类型&#xff0c;比如体重、身高、收入、价格等&#xff0c;在介绍ID3&#xff0c;C4.5其核心是信息熵…

sklearn 决策树例子_sklearn CART决策树分类

sklearn CART决策树分类 决策树是一种常用的机器学习方法&#xff0c;可以用于分类和回归。同时&#xff0c;决策树的训练结果非常容易理解&#xff0c;而且对于数据预处理的要求也不是很高。 理论部分 比较经典的决策树是ID3、C4.5和CART&#xff0c;分别分析信息增益、增益率…

机器学习--详解CART树剪枝原理和过程

这一节主要讲前面多次的提到的决策树问题&#xff0c;前面的决策树生成算法递归的产生决策树&#xff0c;直到不能继续分支或者达到要求为止&#xff0c;这样的决策树往往对训练数据的分类很准确&#xff0c;因为他就是基于训练数据的熵或者基尼不存度进行分类的&#xff0c;因…

【树模型与集成学习】(task2)代码实现CART树(更新ing)

学习心得 task2学习GYH大佬的回归CART树&#xff0c;并在此基础上改为分类CART树。 更新ing。。 这里做一些对决策树分裂依据更深入的思考引导&#xff1a;我们在task1证明离散变量信息增益非负时曾提到&#xff0c;信息增益本质上就是联合分布和边缘分布乘积的kl散度&#xf…

CART 决策树

ID3使用信息增益&#xff0c;而C4.5使用增益比率进行拆分。 在此&#xff0c;CART是另一种决策树构建算法。 它可以处理分类和回归任务。 该算法使用名为gini索引的新度量标准来创建分类任务的决策点。 CART树的核心是决策规则将通过GINI索引值决定。 停止条件。 如果我们继续…

CART决策树算法

在进行自动识别窃漏电用户分析实战时&#xff0c;用到了CART决策树算法&#xff0c;所以整理记录该算法的内容。内容整理参考文档决策树——CART算法及其后的参考文章。 一、CART&#xff08;classification and regression tree&#xff09;分类与回归树&#xff0c;既可用于…

CART树算法解析加举例

算法步骤 CART假设决策树是二叉树&#xff0c;内部结点特征的取值为“是”和“否”&#xff0c;左分支是取值为“是”的分支&#xff0c;右分支是取值为“否”的分支。这样的决策树等价于递归地二分每个特征&#xff0c;将输入空间即特征空间划分为有限个单元&#xff0c;并在…

ID3、C4.5与CART树的联系与区别

ID3、C4.5与CART树的联系与区别&#xff1a; 参考博客&#xff1a; 链接1 链接2 特征选择准则&#xff1a; ID3的特征选择准则为信息增益&#xff0c;即集合D的经验熵H(D)与给定特征A下条件经验熵H(D|A)之差&#xff0c;即&#xff1a; H(D)表现了数据集D进行分类的不确定性…

决策树构建算法—ID3、C4.5、CART树

决策树构建算法—ID3、C4.5、CART树 决策树构建算法—ID3、C4.5、CART树 构建决策树的主要算法ID3C4.5CART三种算法总结对比 决策树构建算法—ID3、C4.5、CART树 构建决策树的主要算法 ID3C4.5CART &#xff08;Classification And Rsgression Tree&#xff09; ID3 ID3算法…

3-6 决策树、CART树、GBDT、xgboost、lightgbm一些关键点梳理

目录 1、决策树 2、CART树 2.1 CART分类树-输入样本特征&#xff1b;输出样本对应的类别(离散型) 2.2 CART回归树-输入样本特征&#xff1b;输出样本的回归值(连续型) 3、GBDT 3.1 提升树 3.2 GBDT 4、xgboost 4.1 损失函数及节点展开 4.2 精确贪心算法及相关近似算法…

CART树回归

说明&#xff1a;本博客是学习《python机器学习算法》赵志勇著的学习笔记&#xff0c;其图片截取也来源本书。 基于树的回归算法是一类基于局部的回归算法&#xff0c;通过将数据集切分成多份&#xff0c;在每一份数据中单独建模。与局部加权线性回归不同的是&#xff0c;基于…

剪枝、cart树

一、剪枝 1. 为什么要剪枝 在决策树生成的时候&#xff0c;更多考虑的是训练数据&#xff0c;而不是未知数据&#xff0c;这会导致过拟合&#xff0c;使树过于复杂&#xff0c;对于未知的样本不准确。 2. 剪枝的依据——通过极小化决策树的损失函数 损失函数的定义为&#x…

【机器学习】决策树——CART分类回归树(理论+图解+公式)

&#x1f320; 『精品学习专栏导航帖』 &#x1f433;最适合入门的100个深度学习实战项目&#x1f433;&#x1f419;【PyTorch深度学习项目实战100例目录】项目详解 数据集 完整源码&#x1f419;&#x1f436;【机器学习入门项目10例目录】项目详解 数据集 完整源码&…

CART树(分类回归树)

主要内容 &#xff08;1&#xff09;CART树简介 &#xff08;2&#xff09;CART树节点分裂规则 &#xff08;3&#xff09;剪枝 --------------------------------------------------------------------------------------------------------------------- 一、简介 CART…

CART树

算法概述 CART(Classification And Regression Tree)算法是一种决策树分类方法。 它采用一种二分递归分割的技术&#xff0c;分割方法采用基于最小距离的基尼指数估计函数&#xff0c;将当前的样本集分为两个子样本集&#xff0c;使得生成的的每个非叶子节点都有两个分支。因此…

Pytorch之view,reshape,resize函数

对于深度学习中的一下数据&#xff0c;我们通常是要变成tensor格式&#xff0c;并且需要对其调整形状&#xff0c;很多时候我们往往只关注view之后的结果&#xff08;比如输出的尺寸&#xff09;&#xff0c;而不关心过程。但有时候还是要关注一下这个到底是怎么变换过来的&…

OpenCV-Python图像处理:插值方法及使用resize函数进行图像缩放

☞ ░ 前往老猿Python博客 https://blog.csdn.net/LaoYuanPython ░ 图像缩放用于对图像进行缩小或扩大&#xff0c;当图像缩小时需要对输入图像重采样去掉部分像素&#xff0c;当图像扩大时需要在输入图像中根据算法生成部分像素&#xff0c;二者都会利用插值算法来实现。 一…

vector的resize函数和reserve函数

博客原文&#xff1a;C基础篇 -- vector的resize函数和reserve函数_VampirEM_Chosen_One的博客-CSDN博客&#xff0c;写的特别好&#xff0c;谢谢原博主。 正文&#xff1a; 对于C的vector容器模板类&#xff0c;存在size和capacity这样两个概念&#xff0c;可以分别通过vect…

OpenCV 图片尺寸缩放——resize函数

文章目录 OpenCV中的缩放&#xff1a;resize函数代码案例 OpenCV中的缩放&#xff1a; 如果要放大或缩小图片的尺寸&#xff0c;可以使用OpenCV提供的两种方法&#xff1a; resize函数&#xff0c;是最直接的方式&#xff1b;pyrUp&#xff0c;pyrDown函数&#xff0c;即图像…