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

article/2025/9/24 15:53:13

文章目录

    • 决策树的介绍
    • CART决策树算法简介
      • 基尼指数
    • CART决策树生成算法及Python代码实现

决策树的介绍

决策树是以树的结构将决策或者分类过程展现出来,其目的是根据若干输入变量的值构造出一个相适应的模型,来预测输出变量的值。预测变量为离散型时,为分类树;连续型时,为回归树。
常用的决策树算法:

算法简介
ID3使用信息增益作为分类标准 ,处理离散数据,仅适用于分类树。
CART使用基尼系数作为分类标准,离散、连续数据均可,适用于分类树,回归树。
C4.5使用信息增益和增益率相结合作为分类标准,离散、连续数据均可,但效率较低,适用于分类树
C5.0是C4.5用于大数据集的拓展,效率较高

CART决策树算法简介

  1. CART算法是二分类常用的方法,由CART算法生成的决策树是二叉树,而 ID3 以及 C4.5 算法生成的决策树是多叉树,从运行效率角度考虑,二叉树模型会比多叉树运算效率高。
  2. CART算法通过基尼(Gini)指数来选择最优特征。

基尼指数

基尼系数代表模型的不纯度,基尼系数越小,则不纯度越低。

CART决策树使用“基尼指数”来选择划分属性,数据集D的纯度可以用基尼值来度量:![在这里插入图片描述](https://img-blog.csdnimg.cn/d61a773ee541455ab990290774bf1482.png

直观来说,G i n i ( D )反映了从数据集D中随机抽取两个样本,其类别标记不一致的概率。因此,G i n i ( D ) 越小,则数据集D 的纯度越高.

属性a的基尼指数定义为
在这里插入图片描述
所以我们在候选属性集合A中,选择那个使得划分后基尼指数最小的属性作为最优划分属性,即在这里插入图片描述

假设使用特征 A 将数据集 D 划分为两部分 D1 和 D2,此时按照特征 A 划分的数据集的基尼系数为:
在这里插入图片描述

CART决策树生成算法及Python代码实现

输入:训练数据集D,停止计算的条件
输出:CART决策树

(1)构造训练数据集(人的年龄、工作、房产以及信誉)

# 构造数据集
def create_dataset():dataset = [['youth', 'no', 'no', 'just so-so', 'no'],['youth', 'no', 'no', 'good', 'no'],['youth', 'yes', 'no', 'good', 'yes'],['youth', 'yes', 'yes', 'just so-so', 'yes'],['youth', 'no', 'no', 'just so-so', 'no'],['midlife', 'no', 'no', 'just so-so', 'no'],['midlife', 'no', 'no', 'good', 'no'],['midlife', 'yes', 'yes', 'good', 'yes'],['midlife', 'no', 'yes', 'great', 'yes'],['midlife', 'no', 'yes', 'great', 'yes'],['geriatric', 'no', 'yes', 'great', 'yes'],['geriatric', 'no', 'yes', 'good', 'yes'],['geriatric', 'yes', 'no', 'good', 'yes'],['geriatric', 'yes', 'no', 'great', 'yes'],['geriatric', 'no', 'no', 'just so-so', 'no']]features = ['age', 'work', 'house', 'credit']return dataset, features

(2)根据公式计算现有特征对该数据集的基尼指数

计算当前集合的Gini指数:

# 计算当前集合的Gini系数
def calcGini(dataset):# 求总样本数num_of_examples = len(dataset)labelCnt = {}# 遍历整个样本集合for example in dataset:# 当前样本的标签值是该列表的最后一个元素currentLabel = example[-1]# 统计每个标签各出现了几次if currentLabel not in labelCnt.keys():labelCnt[currentLabel] = 0labelCnt[currentLabel] += 1# 得到了当前集合中每个标签的样本个数后,计算它们的p值for key in labelCnt:labelCnt[key] /= num_of_exampleslabelCnt[key] = labelCnt[key] * labelCnt[key]# 计算Gini系数Gini = 1 - sum(labelCnt.values())return Gini

将当前样本集分割成特征i取值为value的一部分和取值不为value的一部分(二分):

def split_dataset(dataset, index, value):sub_dataset1 = []sub_dataset2 = []for example in dataset:current_list = []if example[index] == value:current_list = example[:index]current_list.extend(example[index + 1 :])sub_dataset1.append(current_list)else:current_list = example[:index]current_list.extend(example[index + 1 :])sub_dataset2.append(current_list)return sub_dataset1, sub_dataset2

(3)选择基尼指数最小的值对应的特征为最优特征,对应的切分点为最优切分点(若最小值对应的特征或切分点有多个,随便取一个即可)

def choose_best_feature(dataset):# 特征总数numFeatures = len(dataset[0]) - 1# 当只有一个特征时if numFeatures == 1:return 0# 初始化最佳基尼系数bestGini = 1# 初始化最优特征index_of_best_feature = -1# 遍历所有特征,寻找最优特征和该特征下的最优切分点for i in range(numFeatures):# 去重,每个属性值唯一uniqueVals = set(example[i] for example in dataset)# Gini字典中的每个值代表以该值对应的键作为切分点对当前集合进行划分后的Gini系数Gini = {}# 对于当前特征的每个取值for value in uniqueVals:# 先求由该值进行划分得到的两个子集sub_dataset1, sub_dataset2 = split_dataset(dataset,i,value)# 求两个子集占原集合的比例系数prob1 prob2prob1 = len(sub_dataset1) / float(len(dataset))prob2 = len(sub_dataset2) / float(len(dataset))# 计算子集1的Gini系数Gini_of_sub_dataset1 = calcGini(sub_dataset1)# 计算子集2的Gini系数Gini_of_sub_dataset2 = calcGini(sub_dataset2)# 计算由当前最优切分点划分后的最终Gini系数Gini[value] = prob1 * Gini_of_sub_dataset1 + prob2 * Gini_of_sub_dataset2# 更新最优特征和最优切分点if Gini[value] < bestGini:bestGini = Gini[value]index_of_best_feature = ibest_split_point = valuereturn index_of_best_feature, best_split_point

(4)按照最优特征和最优切分点,从现结点生成两个子结点,将训练数据集中的数据按特征和属性分配到两个子结点中;

删除某特征值为value值的样本后获取到的数据集:

# 提取子集合
# 功能:从dataSet中先找到所有第axis个标签值 = value的样本
# 然后将这些样本删去第axis个标签值,再全部提取出来成为一个新的样本集
def create_sub_dataset(dataset, index, value):sub_dataset = []for example in dataset:current_list = []if example[index] == value:current_list = example[:index]current_list.extend(example[index + 1 :])sub_dataset.append(current_list)return sub_dataset

(5)对两个子结点递归地调用(2)(3)(4),直至满足停止条件。
(6)生成CART树。
算法停止的条件:结点中的样本个数小于预定阈值,或样本集的基尼指数小于预定阈值(样本基本属于同一类,如完全属于同一类则为0),或者特征集为空。

特征被使用完毕返回处理:

# 返回具有最多样本数的那个标签的值('yes' or 'no')
def find_label(classList):# 初始化统计各标签次数的字典# 键为各标签,对应的值为标签出现的次数labelCnt = {}for key in classList:if key not in labelCnt.keys():labelCnt[key] = 0labelCnt[key] += 1# 将classCount按值降序排列# 例如:sorted_labelCnt = {'yes': 9, 'no': 6}sorted_labelCnt = sorted(labelCnt.items(), key = lambda a:a[1], reverse = True)# 下面这种写法有问题# sortedClassCount = sorted(labelCnt.iteritems(), key=operator.itemgetter(1), reverse=True)# 取sorted_labelCnt中第一个元素中的第一个值,即为所求return sorted_labelCnt[0][0]

生成决策树的代码:

def create_decision_tree(dataset, features):# 求出训练集所有样本的标签# 对于初始数据集,其label_list = ['no', 'no', 'yes', 'yes', 'no', 'no', 'no', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'no']label_list = [example[-1] for example in dataset]# 先写两个递归结束的情况:# 若当前集合的所有样本标签相等(即样本已被分“纯”)# 则直接返回该标签值作为一个叶子节点if label_list.count(label_list[0]) == len(label_list):return label_list[0]# 若训练集的所有特征都被使用完毕,当前无可用特征,但样本仍未被分“纯”# 则返回所含样本最多的标签作为结果if len(dataset[0]) == 1:return find_label(label_list)# 下面是正式建树的过程# 选取进行分支的最佳特征的下标和最佳切分点index_of_best_feature, best_split_point = choose_best_feature(dataset)# 得到最佳特征best_feature = features[index_of_best_feature]# 初始化决策树decision_tree = {best_feature: {}}# 使用过当前最佳特征后将其删去del(features[index_of_best_feature])# 子特征 = 当前特征(因为刚才已经删去了用过的特征)sub_labels = features[:]# 递归调用create_decision_tree去生成新节点# 生成由最优切分点划分出来的二分子集sub_dataset1, sub_dataset2 = split_dataset(dataset,index_of_best_feature,best_split_point)# 构造左子树decision_tree[best_feature][best_split_point] = create_decision_tree(sub_dataset1, sub_labels)# 构造右子树decision_tree[best_feature]['others'] = create_decision_tree(sub_dataset2, sub_labels)return decision_tree

利用训练好的决策树对新的样本进行分类测试:

# 用上面训练好的决策树对新样本分类
def classify(decision_tree, features, test_example):# 根节点代表的属性first_feature = list(decision_tree.keys())[0]# second_dict是第一个分类属性的值(也是字典)second_dict = decision_tree[first_feature]# 树根代表的属性,所在属性标签中的位置,即第几个属性index_of_first_feature = features.index(first_feature)# 对于second_dict中的每一个keyfor key in second_dict.keys():# 不等于'others'的keyif key != 'others':if test_example[index_of_first_feature] == key:# 若当前second_dict的key的value是一个字典if type(second_dict[key]).__name__ == 'dict':# 则需要递归查询classLabel = classify(second_dict[key], features, test_example)# 若当前second_dict的key的value是一个单独的值else:# 则就是要找的标签值classLabel = second_dict[key]# 如果测试样本在当前特征的取值不等于key,就说明它在当前特征的取值属于'others'else:# 如果second_dict['others']的值是个字符串,则直接输出if isinstance(second_dict['others'],str):classLabel = second_dict['others']# 如果second_dict['others']的值是个字典,则递归查询else:classLabel = classify(second_dict['others'], features, test_example)return classLabel

main函数:

if __name__ == '__main__':dataset, features = create_dataset()decision_tree = create_decision_tree(dataset, features)# 打印生成的决策树print(decision_tree)# 对新样本进行分类测试features = ['age', 'work', 'house', 'credit']test_example = ['midlife', 'yes', 'no', 'great']print(classify(decision_tree, features, test_example))

运行结果解析:
在这里插入图片描述
根据结果画出的决策树:
在这里插入图片描述
对样本分类测试的结果:
yes。


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

相关文章

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;即图像…

OpenCV的resize函数优化

背景 在使用OpenCV做图像处理的时候&#xff0c;最常见的问题是c版本性能不足&#xff0c;以resize函数为例来说明&#xff0c;将size为[864,1323,3]的函数缩小一半&#xff1a; Mat img0;gettimeofday(&t4, NULL);cv::resize(source, img0, cv::Size(cols_out,rows_out)…