入门机器学习(西瓜书+南瓜书)决策树总结(python代码实现)

news/2024/7/9 10:58:12 标签: 人工智能, sklearn

入门机器学习(西瓜书+南瓜书)决策树总结(python代码实现)

一、决策树理论分析

1.1 通俗理解

决策树是一种非常经典的机器学习算法,通俗理解的话我们可以举一个例子,比如现在别人要找你借钱,那么按照首先是不是要判断你和他的关系如何?如果关系不好,我就直接拒绝他。如果关系很好,我就直接借给他了,那么如果关系一般,我要判断一下他是男是女?如果是男生,那么就不借,如果是女生,我要继续考虑她的人品好不好?如果人品不好,就不借,如果人品不错,就借。这也就是所谓的决策树。用python画出决策树的图,可以看到相当的直观。也可以说是一个决策的依据。
在这里插入图片描述

1.2 理论分析

决策树(decision tree)是一种常用的机器学习算法,是一种描述对实例进行分类的树形结构。而之前的一个决策树构造,我们往往是根据“经验”来进行构造的,而这些“经验都是来自于我们平时的获取数据”。因此决策树的合理构造也需要数据。
为了便于理解,我们介绍下一个实际的例子。借贷公司根据借贷人是否有房子,是否有工作来决定是否给借贷人发放贷款。

如下图所示是我们根据数据构造的决策树,你或许会有很多问题,比如我是先判断他是否有房子,还是先判断他是否有工作呢?这也是要构造决策树需要解决的问题。
决策树属于是基于“树”结构来进行决策。
这个树的内部节点也就是方形的内容代表数据集的属性,也就是借钱人的性别啊,关系啊,人品啊,而分支呢?就是属性的取值,也就是性别是男还是女。而最后的叶子节点(通俗来说就是树向下最后一个节点),就是yes和no。这就是一个决策时包含的内容。
在这里插入图片描述

1.3 构造方法

1.3.1 这“棵树怎么长”?

读了上面的内容你就认为你学会了决策树吗?这还仅仅理论内容,实际的代码实现需要算法的思想。因为涉及到树,所以递归属于最核心的算法,构造决策树的策略“分而治之”,决策树的构造是实际上是自根至叶的递归过程。更通俗来说就是说这“棵树怎么长”?
(1)选择一个最优的属性,根据属性值划分成若干个子集;
(2)在每个子集继续构造决策树。

1.3.2 这棵树长到什么时候停?

其中有三种情形导致递归返回,也就是说这棵树长到什么时候停?
(1)当前节点包含的样本全属于同一类别,无需划分;(比如给出的数据都是同意贷款,那么决策树就是一个agree,无需划分。)
在这里插入图片描述

(2)当前属性集为空,或是所有样本在所有属性上的取值都相同,无法划分。(给出的数据都是有房子,没工作,无法根据属性值划分,递归返回)
在这里插入图片描述

(3)当前结点包含的样本集合为空,不能划分。(很容易理解,空的递归返回)

1.4 属性划分选择

其实构造决策树的关键是如何选择最优划分属性。一般而言,随着划分过程的不断进行,我们希望划分后可以分出更多的结果,也就是节点的纯度越来越高。
常用的划分准则有
ID3:信息增益;
C4.5:增益率;
CART:基尼指数
要说清楚这些问题,我们不得不说一下信息熵的概念。

1.4.1 信息熵

信息奠基人香农(Shannon)认为“信息是用来消除随机不确定性的东西”,也就是说衡量信息量的大小就是看这个信息消除不确定性的程度。
“太阳从东边升起”,这条信息并没有减少不确定性,因为太阳肯定是从东边升起的,这是一句废话,信息量为0。”
2018中国队成功进入世界杯“从直觉上来看,这句话具有很大的信息量。因为中国队进入世界杯的不确定性因素很大,而这句话消除了进入世界杯的不确定性,所以按照定义,这句话的信息量很大。
根据上述可总结如下:信息量的大小与信息发生的概率成反比。概率越大,信息量越小。概率越小,信息量越大。

1.4.2 信息量的计算

设某一事件发生的概率为P(x),其信息量表示为:
I ( x ) = l o g ( P ( x ) ) I(x)=log(P(x)) I(x)=log(P(x))
其中I ( x )表示信息量,这里log表示以e为底的自然对数。就是高中学的lnx。
3.2 信息熵
信息熵也被称为熵,用来表示所有信息量的期望。
期望是试验中每次可能结果的概率乘以其结果的总和。(可以理解最可能获得的结果)
所以信息量的熵可表示为:(这里的X是一个离散型随机变量)
H ( X ) = − ∑ i = 1 n P ( x i ) l o g ( P ( x i ) ) ( X = x 1 , x 2 , x 3 , . . . , x n ) H(X)=-\sum_{i=1}^{n}P(x_{i})log(P(x_{i}))(X=x_{1},x_{2},x_{3},...,x_{n}) H(X)=i=1nP(xi)log(P(xi))(X=x1,x2,x3,...,xn)
对于0-1分布的问题,由于其结果只用两种情况,是或不是,设某一件事情发生的概率为,则另一件事情发生的概率为,所以对于0-1分布的问题,计算熵的公式可以简化如下:
H ( X ) = − ∑ i = 1 n P ( x i ) l o g ( P ( x i ) = − P ( x ) l o g ( P ( x ) ) − ( 1 − P ( x ) ) l o g ( 1 − P ( x ) ) \begin{aligned} H(X)&=-\sum_{i=1}^{n}P(x_{i})log(P(x_{i})\\ &=-P(x)log(P(x))-(1-P(x))log(1-P(x)) \end{aligned} H(X)=i=1nP(xi)log(P(xi)=P(x)log(P(x))(1P(x))log(1P(x))
可以总结,信息熵来说,信息熵越大,那么这个事件X发生的不确定性越大,信息熵越小,这个事件X发生的不确定性越小。例如:事件X发生的概率为1,那么事件X不发生的概率为0.这样带入公式计算,H(X)=0,即代表事件X一定发生,也即不确定性为0。
可以看到信息熵最大的特点就是两个概率一样。信息增益越多说明该特征越重要,回到决策树的话题,我们就是根据信息增益来选择特征构造决策树的,这也是这颗决策树怎么长的解决办法。

1.5 划分准则

1.5.1 ID3:信息增益

信息增益:在划分数据集之前之后信息发生的变化。按照属性的特征值划分数据集,计算信息增益,获得信息增益最高的属性就是最好的选择。
在这里插入图片描述
根据这个准则,需要计算通过不同特征划分后的信息增益率,选择最大值划分数据集,进而构造决策树。信息增益:对可取值数目较多的属性有所偏好,有明显弱点,例如:考虑将“编号”作为一个属性.为了便于读者理解,附上一个例子。
在这里插入图片描述

1.5.2 C4.5:增益率

刚才说到,ID3算法通过信息增益构造决策树,有明显弱点,例如:考虑将“编号”作为一个属性,为了对这一问题改进,产生了C4.5算法,他的划分标准是根据信息增益率划分。
G a i n r a t i o ( D , a ) = G a i n ( D , a ) I V ( a ) 其中 I V ( a ) = − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ l o g 2 ∣ D v ∣ ∣ D ∣ \begin{aligned} Gain_ratio(D,a)=\frac{Gain(D,a)}{IV(a)}\\ 其中IV(a)=-\sum_{v=1}^{V}\frac{|D^v|}{|D|}log_{2}\frac{|D^v|}{|D|} \end{aligned} Gainratio(D,a)=IV(a)Gain(D,a)其中IV(a)=v=1VDDvlog2DDv
属性a的可能取值数目越多(即V越大),则IV(a)的值通常就越大。信息增益比本质: 是在信息增益的基础之上乘上一个惩罚参数。特征个数较多时,惩罚参数较小;特征个数较少时,惩罚参数较大。不过有一个缺点:信息增益率偏向取值较少的特征。为了便于读者理解,举个例子。
在这里插入图片描述

使用信息增益率:基于以上缺点,并不是直接选择信息增益率最大的特征,而是现在候选特征中找出信息增益高于平均水平的特征,然后在这些特征中再选择信息增益率最高的特征。

1.5.3 CART:基尼指数

数学家们想到了另外一个表示纯度的方法,叫做基尼指数。表达式如下:
G i n i ( D ) = ∑ k = 1 ∣ y ∣ ∑ k ′ ≠ k p k p k ′ = ∑ k = 1 ∣ y ∣ p k ( 1 − p k ) = ∑ k = 1 ∣ y ∣ p k − ∑ k = 1 ∣ y ∣ ( 1 − p k ) = 1 − ∑ k = 1 ∣ y ∣ ( 1 − p k ) \begin{aligned} Gini(D)&=\sum_{k=1}^{|y|}\sum_{k^{'}\ne k} p_{k}p_{k^{'}}\\&= \sum_{k=1}^{|y|} p_{k}(1-p_{k})\\ &=\sum_{k=1}^{|y|} p_{k} - \sum_{k=1}^{|y|} (1-p_{k})\\ &=1-\sum_{k=1}^{|y|} (1-p_{k}) \end{aligned} Gini(D)=k=1yk=kpkpk=k=1ypk(1pk)=k=1ypkk=1y(1pk)=1k=1y(1pk)
基尼指数表示在样本集合中一个随机选中的样本被分错的概率。举例来说,现在一个袋子里有3种颜色的球若干个,伸手进去掏出2个球,颜色不一样的概率,这下明白了吧。Gini(D)越小,数据集D的纯度越高。
属性 a 的基尼指数:
G i n i _ i n d e x ( D , a ) = ∑ v = 1 V D v D G i n i ( D v ) Gini\_index(D,a)=\sum_{v=1}^{V}\frac{D^v}{D}Gini(D^v) Gini_index(D,a)=v=1VDDvGini(Dv)
在这里插入图片描述

在候选属性集合中,选取那个使划分后基尼指数最小的属性
以上是划分决策树的计算指标依据,详细内容请见西瓜书75页,南瓜书15页,南瓜书决策树对应配套视频。

1.6 树形结构为什么不需要归一化?

因为数值缩放不影响分裂点位置,对树模型的结构不造成影响。
按照特征值进行排序的,排序的顺序不变,那么所属的分支以及分裂点就不会有不同。而且,树模型是不能进行梯度下降的,因为构建树模型(回归树)寻找最优点时是通过寻找最优分裂点完成的,因此树模型是阶跃的,阶跃点是不可导的,并且求导没意义,也就不需要归一化。

既然树形结构(如决策树RF)不需要归一化,那为何非树形结构比如AdaboostSVMLRKnnKMeans之类则需要归一化。

对于线性模型,特征值差别很大时,运用梯度下降的时候,损失等高线是椭圆形,需要进行多次迭代才能到达最优点。但是如果进行了归一化,那么等高线就是圆形的,促使SGD往原点迭代,从而导致需要的迭代次数较少。

1.7 决策树如何剪枝

决策树的剪枝基本策略有 预剪枝 (Pre-Pruning) 和 后剪枝 (Post-Pruning)。

预剪枝:其中的核心思想就是,在每一次实际对结点进行进一步划分之前,先采用验证集的数据来验证如果划分是否能提高划分的准确性。如果不能,就把结点标记为叶结点并退出进一步划分;如果可以就继续递归生成节点。
后剪枝:后剪枝则是先从训练集生成一颗完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能带来泛化性能提升,则将该子树替换为叶结点。
两种方法的对比:

剪枝方法预剪枝后剪枝
时间开销训练时间开销低,测试时间开销低训练时间开增加,测试时间开销低
过/欠拟合风险过拟合风险降低,欠拟合风险增加过拟合风险降低,欠拟合风险基本不变
泛化性能相对差相对好

1.8 Bagging 与随机森林

随机森林一句话来说就是三个臭皮匠顶个诸葛亮,人多力量大,也就是说一颗树解决不了问题,那就一堆,大家都发表意见,最终取最多的。这也是随机森林的基本思想。

随机森林:以决策树作为基学习器,同时引入了随机属性选择。即先从属性集合(假定有d个属性)中随机选择一个包含k个属性的子集,再从这个子集中选择一个最优属性进行划分.
(1) 当k=d时,基决策树与传统决策树相同.
(2) 当k=1时,则随机选择一个属性用于划分.
一般推荐k=log2d.
在这里插入图片描述

二、代码实现

为了降低读者的门槛,这里仅附上调用sklearn的代码。详细代码小程序员将放在百度网盘,供大家参考。
下面是ex4.csv的内容,大家可以新建一个记事本,拷贝下面内容,然后更改文件后缀名为csv.复现代码。

0,0,0,0,0,0,0
1,0,1,0,0,0,0
1,0,0,0,0,0,0
0,0,1,0,0,0,0
2,0,0,0,0,0,0
0,1,0,0,1,1,0
1,1,0,1,1,1,0
1,1,0,0,1,0,0
1,1,1,1,1,0,1
0,2,2,0,2,1,1
2,2,2,2,2,0,1
2,0,0,2,2,1,1
0,1,0,1,0,0,1
2,1,1,1,0,0,1
1,1,0,0,1,1,1
2,0,0,2,2,0,1
0,0,1,1,1,0,1

训练决策树

from pandas import read_csv
df = read_csv("ex4.csv",header=None)
data = df.values
X = data[:,:-1]
y = data[:,-1]
names_chinese = ['色泽','根蒂','敲声','纹理','脐部','触感']
names_english = ['color','root','sound','texture','navel','feeling']
label_chinese = ['好瓜','坏瓜']
label_english = ['good','bad']
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier(criterion='entropy')
#model = DecisionTreeClassifier(criterion='entropy',max_depth=3)
#model = DecisionTreeClassifier(criterion='entropy',min_samples_leaf=3)
#model = DecisionTreeClassifier(criterion='entropy',min_samples_split=3)
model.fit(X,y)

决策树可视化
这里可视化需要安装graphviz,报错的可以参考这里

from sklearn.externals.six import StringIO
from sklearn.tree import export_graphviz
from pydotplus import graph_from_dot_data
from IPython.display import Image


dot_data = StringIO()
export_graphviz(model,out_file=dot_data,
               feature_names=['color','root','sound','texture','navel','feeling'],\
               class_names=['good','bad'])
graph = graph_from_dot_data(dot_data.getvalue())
Image(graph.create_png()) #在jupyter中直接显示
#graph.write_pdf("tree.pdf")

结果
在这里插入图片描述

三、代码文件

小程序员将代码文件和相关素材整理到了百度网盘里,因为文件大小基本不大,大家也不用担心限速问题。后期小程序员有能力的话,将在gitee或者github上上传相关素材。
链接:https://pan.baidu.com/s/1Ce14ZQYEYWJxhpNEP1ERhg?pwd=7mvf
提取码:7mvf


http://www.niftyadmin.cn/n/1699054.html

相关文章

brew安装Redis redis.conf文件位置

brew install redis 几个命令 brew install redis #brew 安装redis brew list redis #查看redis安装的位置 cd #打开对应位置 open . #在terminal当前位置打开访达安装都要设置redis.conf 但是redis.conf并不在这个文件夹中 这里有一个homebrew.mxcl.redis.plist…

入门机器学习(西瓜书+南瓜书)神经网络总结(python代码实现)

入门机器学习(西瓜书南瓜书)神经网络总结(python代码实现) 一、神经网络 1.1 通俗理解 这次的内容较难理解,因此,笔者尽量通过通俗易懂的话来说说究竟什么是神经网络?他是怎么来的&#xff1…

redis成功启动配置文件不生效

redis成功启动配置文件不生效 个人贪图简便,使用brew安装redis,可在任何位置直接启动redis,有以下操作 redis-server & redis-server & /usr/local/etc/redis.conf这两种方式都能成功启动redis,但是在redis.conf中设置的…

数据库oracle 11g 的日志管理

1、查询oracle日志的路径SQL> show parameter dump_dest NAME TYPE VALUE------------------------------------ ----------- ------------------------------background_dump_dest string /home/oracle/app/oracle/…

redis五大数据类型与三种特殊数据类型

Redis五大数据类型 StringListSetHashZset Redis官方介绍 Redis是内存中的数据结构存储系统,可以作用数据库、缓存、消息中间MQ支持多种数据类型 String字符串hash散列list列表set 集合sorted sets有序集合bimemapshyperlogloggeospatial Redis内置了主从复制rep…

入门机器学习(西瓜书+南瓜书)支持向量机总结(python代码实现)

入门机器学习(西瓜书南瓜书)支持向量机总结(python代码实现) 一、支持向量机 1.1 通俗理解 通俗来说,支持向量机这玩意就是用一条直线把不同的样本的分开,具体可以看下图。可以看到就目前的数据分布&…

vc++比较三个数的大小

#include "stdio.h" main() { int a,b,c,temp; printf("输入三个整数:\n"); scanf("%d%d%d",&a,&b,&c); if (a>b) {tempa;ab;btemp;} if (a>c) {tempa;ac;ctemp;} if (b>c) {tempb;bc;ctemp;} printf("Min…

ES6作用域和解构赋值

ES6 强制开启严格模式 作用域 var 声明局部变量,for/if花括号中定义的变量在花括号外也可访问let 声明的变量为块作用域,变量不可重复定义const 声明常量,块作用域,声明时必须赋值,不可修改// const声明的k指向一个对象…