机器学习决策树:提炼出分类器算法
前面三天推送了决策树的基本原理和选择最佳分裂特征的几种公式,用到决策树一般都会出现过拟合问题,因此需要对决策树进行剪枝,阐述了常用的几种剪枝的方法(这些方法都出现在了sklearn的决策树构造函数的参数中),后面总结了sklearn调包分析用决策树做分类和回归的几个例子,下面通过一个简单的例子,提炼出构建一棵分类决策树的算法思想,进一步体会下决策树的分类原理。
1 数据集介绍
有一堆苹果,现在要分析下哪些苹果是好的,哪些是坏的,主要根据三个特征:大小,颜色,和形状进行区分。其中大小这个特征的取值:大和小;颜色特征的取值为:红色和青色;形状的取值有:圆形和非规则。现在拿到一批已检验的数据:
编号 大小 颜色 形状 好果
1 大 红色 圆形 是
2 大 红色 非规则 是
3 大 红色 圆形 是
4 大 青色 圆形 否
5 大 青色 非规则 否
6 小 红色 圆形 是
7 大 青色 非规则 否
8 小 红色 非规则 否
9 小 青色 圆形 否
10 小 青色 非规则 否
2 sklearn分类结果
调用sklearn的API直接对上述结果分类,编写代码如下:
import numpy as np
from sklearn import tree
import graphviz
#大为1,红为1,圆形为1, 好果为1
data = np.array([[1,1,1,1],
[1,1,0,1],
[1,1,1,1],
[1,0,1,0],
[1,0,1,0],
[0,1,1,1],
[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,0]])
clf = tree.DecisionTreeClassifier()
clf.fit(data[:,0:3],data[:,3])
dot_data = tree.export_graphviz(clf, out_file=None,
feature_names=["magnitude","color","shape"],
class_names=["bad","good"],
filled=True, rounded=True,
special_characters=True)
graph = graphviz.Source(dot_data)
graph
得的的决策树如下所示,根节点选择的特征为颜色,并且判断条件为小于0.5,可以看出它是取值[0,1]的中间值作为不等式的判断条件,基尼系数为0.48,也就是说鱼龙混杂度还是挺大的,可以看到此时value有6个坏果>4个好果,所以这个根节点的类别被标记为坏果。
接下来根据属性的取值,分裂根节点,如果颜色是青色的,则得到一个叶节点,此时的基尼系数为0,说明得到的这类别是纯的,都为坏果,样本个数为5个。如果颜色是红色的,得到一个非叶节点,此时的基尼系数变小了一点,说明获得了一些信息增益。
第二步,我们去掉一个颜色特征,从大小和形状中选择一个最佳的特征进行分裂,结果选择形状作为第二个分裂特征,这个节点对应的样本中:1个坏果,4个好果,所以此节点标记为好果,然后根据其取值:如果形状为圆形,则获得一个叶节点,其所有3个果子都是好果,如果形状不规则,则
第三步,又得到一个非叶节点,它的基尼系数变为0.5,但是数量只有2个,则此时拿掉上一个用过的形状特征后,目前只剩下一个特征:大小,小的为坏果,对应的样本数为1的左叶节点,右叶节点为大的果子,则为好果。
至此,决策树根据基尼系数判断最佳特征的构建过程结束。
3 提炼算法
设数据集为T,属性集为 A,则生成决策树的过程可以标记为 treeBuilder(T,A):
- 生成节点node
- 如果T中样本属于同一类别,则将node标记为叶节点,递归返回。
- 如果A为空,将其标记为叶节点,并且此叶节点的类型为T中类型做多的样本(这种情况:应该只有一种类型了吧,如第2节的最深一层的两个叶节点,此时的属性都已用完,各自都只剩下自己那一类了),递归返回。
- 从属性集A中选择最优化分属性A*,sklearn选择最优的划分属性所用的算法是优化的CART算法。
- 对A*的最优划分属性的几个取值依次遍历: 如果 A*j(第j个取值)对应的在T中的子集合T_Sub个数大于0,则: A = A-A* 递归调用 treeBuilder(T_Sub, A)
如果 T_Sub个数等于0,我们还需要添加一个节点吗?需要的,虽然在当前数据集上这个属性的样本点为空,并不代表在未来的测试集上这个属性对应的样本点还为空,这也是提高决策树的泛化能力的一个方法。
将这个节点为叶节点,并且这个叶节点的类型标记为T中样本点最多的那个类型,递归返回。
调用上述算法后,最终得到一个以node为根节点的决策树。
算法说明:
1. 递归返回的条件有3个:
- T中样本属于同一类别;
- 可用属性为0
- 某个特征的第 j 个取值在T上的样本点个数为0
2. 需要理解递归返回的第3个条件,为什么训练集上出现个数为0时,还要构造一个叶节点,这是为了提高其泛化能力,并且此叶节点的类型标记为父节点的类型,这是把父节点的样本分布作为当前叶节点的先验分布。
让我们看一下远边优美的风景,放松一下吧!
4 总结
好了以上就是决策树的用于分类的总结,关于决策树做回归的问题,等以后对其更深刻地认识后再专门总结这块吧。
您知道先验概率和后验概率到底是怎么回事吗? 贝叶斯公式是怎么得来的? 它为什么能做分类呢?
明天通过2个易懂的来自于生活的小例子来阐述以上问题,欢迎您的关注!
- Hive的left join、left outer join和left semi join三者的区别
- 52. Socket Server 自定义协议的简单实现 | 厚土Go学习笔记
- dataguard备库的数据文件的迁移(r8笔记第22天)
- 46. 实现一个简单的网络爬虫 | 厚土Go学习笔记
- 45. sync.Mutex 互斥和互斥锁 | 厚土Go学习笔记
- golang进度条
- 44. goroutine、channel、time的例子 | 厚土Go学习笔记
- AVL二叉树
- Golang:使用 httprouter 构建 API 服务器
- dataguard中需要注意的一些数据文件操作(r8笔记第21天)
- 42. select 的默认分支 | 厚土Go学习笔记
- 执行计划变化导致CPU负载高的问题分析 (r8笔记第20天)
- 数据结构基础(2) --顺序查找 ; 二分查找
- 数据结构基础(1) --Swap ; Bubble-Sort ; Select-Sort
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 面经手册 · 第11篇《StringBuilder 比 String 快?空嘴白牙的,证据呢!》
- domReady的理解
- Map集合排序
- Chrome 技术篇-一台电脑设置多个独立chrome方法。chrome独立多开技术。
- 023.Ubuntu常见个性化配置
- 快速学习-ElasticJob的FAQ
- 设计模式~状态模式
- 程序员该造轮子吗,造轮子能升职加薪吗?
- 1.基本标签
- 细品mysql之Join 语句的执行过程
- A Java Fork/Join Framework(Doug Lea 关于java Fork/Join框架的论文翻译)
- Mysql 的安装
- Spring系列之数据源的配置 数据库 数据源 连接池的区别
- STM32F4 SPI DMA
- 快速学习-XXL-JOB总体设计