机器学习 - 决策树学习中如何进行分类预测


李俊才 的 CSDN 博客
邮箱 :291148484@163.com
CSDN 主页https://blog.csdn.net/qq_28550263?spm=1001.2101.3001.5343
本文地址https://blog.csdn.net/qq_28550263/article/details/114995553

目 录


1. 决策树建树回顾

2. 实现决策树分类预测的思路

  • 2.1 单条数据的预测
  • 2.2 在数据集上做预测

3. 使用递归查询编程实现分类

4. 寻找预剪枝最佳参数


1. 决策树建树回顾

在阅读本文之前,你应该掌握如何去建立一颗决策树。由于不同的决策树存储结构算法的实现细节上存在一定的差异,因此本文源代码实现对决策树的索引是基于我之前的一篇博文【决策树如何分裂以扩展节点】中所建立的决策树而实现的。

通过该博文我给出的源码运行后可以得到类似于这样一颗决策树:

# 训练参数:{features=features, max_depth=3, min_samples_split=1000, impurity_t='entropy',selector_t = 'majority_label'}
{'depth': 1,                                  # 这里是根节点,深度为1'the_best_feature': 'blueTowersDestroyed',   # 节点对应选出的最佳特征'bestfeature_values': [0, 1, 2, 3, 4],       # 最佳特征的所有取值,也就是'branchs'列表中的分支'samples': 7903,                             # 当前节点处剩余的样本数,根节点处的样本数即测试数据集初始样本数'label': 0,                                  # 节点提前结束分裂(剪枝)时则作为叶节点将使用的标签'branchs': [                                 # 分支列表,列表中的每个元素都是一个子节点{# 根节点的第 1 个子节点'branch': 0,                                  # 作为子节点来子父节点的分支(父节点最佳特征的一个取值)'depth': 2, 'the_best_feature': 'redTowersDestroyed',     # 最佳特征'bestfeature_values': [0, 1, 2],              # 最佳特征的所有取值(所有分支名)'samples': 7533,                              # 节点处剩余样本数'label': 0,                                   # 节点提前结束分裂(剪枝)时则作为叶节点将使用的标签'branchs': [                                  # 分支列表,列表中的每个元素都是一个子节点{'branch': 0, 'depth': 3, 'the_best_feature': 'brTotalGold', 'bestfeature_values': [0, 1, 2, 3, 4], 'samples': 7231, 'label': 0}, {'branch': 1, 'depth': 3, 'the_best_feature': 'brTotalGold', 'bestfeature_values': [0, 1, 2, 3, 4], 'samples': 279, 'label': 0}, {'branch': 2, 'depth': 3, 'the_best_feature': 'brTotalGold', 'brTotalGold', 'bestfeature_values': [0, 1], 'samples': 23, 'label': 0}]}, {# 根节点的第 2 个子节点'branch': 1, 'depth': 2, 'the_best_feature': 'redTowersDestroyed', 'bestfeature_values': [0, 1, 2], 'samples': 340, 'label': 1}, {# 根节点的第 3 个子节点'branch': 2, 'depth': 2, 'the_best_feature': 'redHeralds', 'bestfeature_values': [0, 1], 'samples': 23, 'label': 1}, {# 根节点的第 4 个子节点'branch': 3, 'depth': 2, 'the_best_feature': 'blueWardsPlaced', 'bestfeature_values': [0, 1, 4], 'samples': 6, 'label': 1}, {# 根节点的第 5 个子节点'branch': 4, 'depth': 2, 'the_best_feature': 'blueWardsPlaced', 'bestfeature_values': [1], 'samples': 1, 'label': 1}]
}

为了帮助读者理解,我绘制了该决策树的图形结构示意:

可以看到,在一颗树中节点的本质属性是作为父亲的分支。也就是父节点在依据最佳特征不同的特征值分支后,不同分支再次划分数据集的时候也可以选相同的最佳特征,毕竟同一次分支后的子数据集中拥有的特征类型都是一样的。

该树最简单的样子是这样(但是我们并没有记录成这样而是保留了更多信息,为以后可能的剪枝策略提供数据支持):

[                # root[0,1,2],     # root的分支12,           # root的分支23,           # root的分支34            # root的分支4
]

即:

2. 实现决策树分类预测的思路

2.1 单条数据的预测

★ 先假设有一种情况:
建立决策树没有进行过任何剪枝,并且在每一次分裂中都训练到节点数据集中的所有标签恰好都能一致(只剩下最后一种标签)时。给定一条"测试集"数据并在再次恰好时在训练集中学到过的数据,分类器该如何给出这条数据的标签?

2.2 在数据集上做预测

在数据集上做预测,这个数据集在我们的实验项目里也就是所谓的“测试集”,在测试集上做预测的目的是评估我们模型性能的好坏。而在实践项目里就是所谓的未知数据,从哲学上看是将我们的模型用于改造世界的过程。
计算机思维,就是所有事情都要一步一步地来实现,正如古语所云:天下大事必作于细。数据的预测也是如此,在某个数据集上进行预测,本质就是对数据集中的每一条数据逐一预测并依次记录下预测结果。

def predict(tree, test_datas):'''预测测试集中数据标签使用它调用predict_one()对训练集中的每一条数据一次预测获取预测结果Parameters----------tree:          基于字典的树形结构的一组数据,是我们训练好的决策树test_datas:    测试数据集,包含多条待预测分类标签的数据。'''test_datas = np.array([test_datas]) if len(test_datas.shape) == 1 else test_dataspredict_list = []                     # 训练结果容器# 对每一条数据依次调用predict_one()方法预测并以及将结果装入训练结果容器for one_test_data in test_datas:one_pre_value = predict_one(tree, one_test_data)     # 计算出一条数据的预测标签predict_list.append(one_pre_value)                       # 将这一条数据的预测标签插入预测标签列表predict_list中return np.array(predict_list)

3. 使用递归查询编程实现分类

class ClassificationTree(object):... # 上面的内容请在关联博文中阅读,请尝试文中博文链接def predict_one(self, tree, one_test_data):"""预测测试集中的一条数据这个过程实际上就是基于节点的递归查询过程,在某个节点:是否有分支:- 有分支:必为非叶子节点:使用测试集该节点对应的特征名索引出测试特征值,决定接下来查询的分支:如测试数据的特征值在分支列表中,进入特征值决定的分支,递归以上过程。如测试数据的特征值不在分支列表中,说明是训练时没有遇到过的新情况:可以用投票器投出一个标签:即可以按照该节点数据集的标签集各标签占比投票一个,也可以直接选该节点标签集中出现次数最多的标签作为投票结果。- 无分支:必为叶子节点:返回叶子节点处的标签值为预测结果。Parameters----------tree:           递归过程中的树(除了根节点是原决策树,其它的节点都是其子树);one_test_data:  单条测试数据,本质是单条数据各个特征的取值。Returns-------label,           str 或 int、float等,为一条数据的标签"""# 先将测试的这单条数据与原始的特征名依次组合成字典以待查询onetestdata_dict = dict(zip(self.features,list(one_test_data)))the_best_feature = tree.get('the_best_feature')   # 当前的节点(特征名)branchs = tree.get('branchs')                     # 当前特征节点下树的所有分支,是一个包含分支的列表if branchs == None:           # 没有分支时,时叶子节点return tree.get('label')  # 返回叶子节点处的标签else:                         # 否则是非叶子节点node_values = tree['bestfeature_values']                # 获取该非叶子节点所有分支值feature_value = onetestdata_dict.get(the_best_feature)  # 这条数据中当前特征对应的标签值if feature_value not in node_values:   # 这条来自测试集的特征值没有在训练时出现过(未学习到的样本)return tree.get('label')           # 不得不终止递归预测,返回本节点处的预测标签else:                                  # 仍然在学习到的分支中for i in range(len(branchs)):if branchs[i].get('branch') == feature_value:subtree = branchs[i]                                  # 进入该分支(获取子节点)return self.predict_one(subtree, one_features_data)   # 递归预测之def predict(self, test_datas):assert len(test_datas.shape) == 1 or len(test_datas.shape) == 2 # 只能是1维或2维'''预测测试集中数据标签使用它调用self.predict_one()对训练集中的每一条数据一次预测获取预测结果'''if len(test_datas.shape) == 1: test_datas= np.array([test_datas])tree = self.tree                      # 准备决策树predict_list = []                     # 训练结果容器# 对每一条数据依次调用predict_one()方法预测并以及将结果装入训练结果容器for one_features_data in test_datas:one_pre_value = self.predict_one(tree, one_features_data)   # 计算出一条数据的预测标签predict_list.append(one_pre_value)                          # 将这一条数据的预测标签插入预测标签列表predict_list中return np.array(predict_list)

4. 寻找预剪枝最佳参数

这是对你的计算机来说可能一个比较麻烦的事情,因为一般我们是通过遍历参数的取值,比较不同取值下在测试集上的预测性能来调整参数的。我们在之前的博文中已经讨论过,在决策树中很多预剪枝参数有一个缺点就是,在进行预测之初是不好确定这些参数到底取哪一个值才能获得最佳性能。既然不好预先确定,自然就只剩下训练后再调整它们的这种方法了。

看起来,我们需要先划定一个参数范围,毕竟每次训练都是要耗费一定的时间成本的,受限于计算机算力,我们难以做到便利无数参数。

# 需要在训练后调整的超参数们和他们的取值
parameters = {'impurity_t':['entropy', 'gini'], 'max_depth': range(2, 6), 'min_samples_split': [100, 200, 400, 500, 800],#"selector_t" : ["majority_label","random"],#"RANDOM_SEED":[100,500,1000,2000,4000,8000]   # 当 selector_t = random 时还可以测试随机种子对分类的影响
}

接下来,我们需要对所有的参数进行逐个比较,获取性能指标,在指标中取优。

max_acc = 0
max_acc_parameters = None
def one_test(features,max_depth,min_samples_split,impurity_t,selector_t,x_train,y_train,x_test,y_test):global max_accglobal max_acc_parametersclt = ClassificationTree(features, max_depth, min_samples_split, impurity_t, selector_t,test=True)clt.fit(x_train, y_train)p_test = clt.predict(x_test)test_acc = accuracy_score(p_test, y_test)print("max_depth:",max_depth, "min_samples_split:",min_samples_split, "impurity_t:",impurity_t, "selector_t:",selector_t,"test_acc:",test_acc)if test_acc > max_acc:max_acc = test_accprint("\n>[更新latest_max_acc]:latest_max_acc=",max_acc)max_acc_parameters = {"max_depth":max_depth, "min_samples_split":min_samples_split, "impurity_t":impurity_t, "selector_t":selector_t,"test_acc":test_acc}print("[更新max_acc_parameters]:",max_acc_parameters)for impurity_t in parameters["impurity_t"]:for max_depth in parameters["max_depth"]:for min_samples_split in parameters["min_samples_split"]:one_test(features,max_depth,min_samples_split,impurity_t,selector_t=selector_t,x_train=x_train,y_train=y_train,x_test=x_test,y_test=y_test)#for selector_t in parameters["selector_t"]:#if selector_t == "random":#for RANDOM_SEED in parameters["RANDOM_SEED"]:#one_test(features,max_depth,min_samples_split,impurity_t,selector_t,x_train,y_train,x_test,y_test)#else:#one_test(features,max_depth,min_samples_split,impurity_t,selector_t,x_train,y_train,x_test,y_test)print("\n【最终测试到】:\nMax_Acc=",max_acc,"\nMax_Acc_Parameters=",max_acc_parameters)

机器学习 - [源码实现决策树小专题]决策树学习中如何进行分类预测相关推荐

  1. 机器学习 - [源码实现决策树小专题]决策树如何分裂以拓展节点(以及在不允许调用sklearn等库的源代码实现)

    机器学习 - 决策树如何分裂以拓展节点 [导读]:节点的分裂是决策树建立重要的一个环节.本文在实现求解最佳特征和划分数据集的基础上带领大家实现如何实现决策树的分裂以拓展节点.最终建立一颗分类树. [下 ...

  2. 机器学习 - [源码实现决策树小专题]决策树中子数据集的划分(不允许调用sklearn等库的源代码实现)

    决策树算法中子数据集的划分 推荐: 本文中的代码另外有采用了TypeScript/JavaScript进行实现的版本.作者关注到,谷歌TensorFlow团队近几年在JavaScript语言上动作频频 ...

  3. [含lw+源码等]微信小程序英语学习平台+后台管理系统[包运行成功]适合计算机毕业设计Java毕设程序设计

  4. 视觉机器学习20讲-MATLAB源码示例(4)-决策树学习算法

    视觉机器学习20讲-MATLAB源码示例(4)-决策树学习算法 1. 决策树学习算法 2. Matlab仿真 3. 仿真结果 4. 小结 1. 决策树学习算法 统计学,数据挖掘和机器学习中的决策树训练 ...

  5. 微信发卡小程序源码-自动发卡小程序源码-带流量主功能

    简介: 此套源码带流量主功能裂变扩展,让你赚个广告收益. 朋友花300大洋互站买来的,源码没有动,而且测试搭建表现良好! 源码功能: 小程序系统/多种卡密领取模式/流量主: 支持:添加分类丨分类介绍丨 ...

  6. 医疗小程序源码_零售小程序源码,零售小程序商城

    零售小程序开发(贺经理:188微1924电2925同号),零售小程序定制,零售小程序源码,零售小程序商城,零售商城小程序,零售小程序平台,零售小程序软件,开发零售小程序,近年来,实体经济转型.商流量红 ...

  7. 微信读书登陆界面java_(JAVA后端)微信小程序-毕设级项目搭建-微信阅读小程序(内含源码,微信小程序+java逻辑后台+vue管理系统)~不求完美,实现就好...

    转载地址:(JAVA后端)微信小程序-毕设级项目搭建-微信阅读小程序(内含源码,微信小程序+java逻辑后台+vue管理系统)~不求完美,实现就好 转载请注明出处 一.环境搭建 相关环境软件:JDK1 ...

  8. [含文档+源码等]微信小程序校园生活小助手+后台管理系统前后分离VUE[包运行成功]

            博主介绍:✌在职Java研发工程师.专注于程序设计.源码分享.技术交流.专注于Java技术领域和毕业设计✌ 项目名称 [含文档+源码等]微信小程序校园生活小助手+后台管理系统前后分离V ...

  9. [含论文+源码等]微信小程序电影购票+后台管理系统源码

    IT源码 <微信小程序电影购票+后台管理系统>该项目含有源码.论文等资料.配套开发软件.软件安装教程.项目发布教程等 本系统包含微信小程序做的电影购票前台和Java做的后台管理系统: 微信 ...

最新文章

  1. 清华放大招!从初中生招起,8年时间培养到博士毕业!内卷也要加速了?
  2. 面向对象语言的new操作
  3. android luajava,android嵌入lua
  4. HTTP [TCP Retransmission] Continuation or non-HTTP traffic[Packet size limited during capture]
  5. Linux下编译opencv
  6. vim删除文件第n行到结尾、或某段内容
  7. 三维家可以导入别人的方案吗_三维激光扫描仪
  8. oracle排序字符,Oracle数据字符集和排序的用法
  9. ls命令 文件和目录属性
  10. Android中ListView数据处理优化
  11. Windows XP / 2003 / Vista 原版光盘镜像(下载)及其主要特征
  12. 计算机辅助求解如何做,计算机辅助求解一元高次方程.pdf
  13. 作用JavaScript访问和操作数据库
  14. 无线路由器怎么改密码
  15. IE11 兼容 ES6
  16. 华为连接wifi显示wifi未连接服务器,华为手机连接WIFI但是无法上网怎么解决
  17. HighNewTech:【2019WAIC世界人工智能大会】上海正式开幕——马化腾的AI深思、二马激辩AI
  18. rust写操作系统 rCore tutorial 学习笔记:实验指导零 创建项目与启动
  19. PWA之 Service worker
  20. 如何防御DDOS等流量攻击

热门文章

  1. 剑指offer——面试题33:把数组排成最小数
  2. Ubuntu怎么截图?一些快捷键备忘
  3. 关于Decision in process状态时间变化的解释
  4. Pytorch + LSTM
  5. Android -- SEGV_MAPERR,SEGV_ACCERR
  6. vue+webapi 实现WebSocket 推送
  7. Populating Next Right Pointers in Each Node I or II
  8. 从拉萨骑行到珠峰大本营
  9. MySQL 基础--时间戳类型
  10. Android中 ExpandableList的使用2