前言
本文的代码部分均采用伪代码+代码的形式,帮助有些想挑战自己的小白同学可以自己通过伪代码敲出代码!
简介
决策树(Decision Tree)是一种十分常用的分类方法。作为一种有监督学习,它对特征属性和样本标签之间的映射关系进行建模。相对于K-近邻算法,决策树的主要优势在于数据形式非常容易理解。而决策树之所以称为树,是因为其处理数据的过程可以用树来表示。理论总是那么难以理解,那我们直接上例子吧
一个例子
表1的数据包括5个样本,其特征分别为A,B,样本标签用L表示。特征值和样本标签都只有两种取值:是,否。

现在,我们先尝试用两个特征来对样本进行划分,并用树结构表示:

从图1中我们可以看出:
当特征A的值为否时(即样本4,5),样本标签均为否。因此我们可以预测当A为否时,无论B为何值,样本标签为否
当特征A的值为是时(即样本1,2,3),此时标签不太好分了(有是,也有否),因此我们再用B来进行划分:
当A为是,B为否时(即样本3),样本标签均为否。因此我们可以预测当A为是,B为否时,样本标签为否。
当A为是,B为是时(即样本1,2),样本标签均为是。因此我们可以预测当A为是,B为是时,样本标签为是。
此时我们就将样本都分完了,如果再给我们一组特征值,我们能够轻松地通过特征值,找到“对应”的样本标签了。是不是很简洁明了?
现在探讨一个问题。显而易见,数据集有多个特征,因而也有多种划分方式(比如对于表1我们也可以先对B进行划分),划分数据集的大原则是:把无序的数据变得更加有序。而哪种数据划分方式是最好的数据划分呢?接下来我们引入熵和信息增益的概念。
熵
不要被这个很学术的名词吓到了哈~其实,只要你了解了这个名词之后,你就可以…拿它去装逼了。
熵这个名字起源于信息论之父克劳德·香农,据说在香农写完信息论之后,冯·诺伊曼建议使用“熵”这个术语,因为大家都不知道它是什么意思。
我的理解是,熵就是信息的不确定性。比如说,一个房间如果全部是口罩,那么它的信息量是很低的,而另一个房间里既有口罩,也有防护服,消毒液等等,我们就说它信息量较大。换言之,可能值越多,信息越不确定,熵越大。给出计算熵的公式:

其中P(xi)为可能值为i的概率,n为可能值的数目。举个例子,对于表1的样本标签,共有两种可能值,其中值为’是’的概率是0.4,值为’否’的概率是0.6,因此其熵为:-0.4log(0.4)-0.6log(0.6) = 0.97
下面贴出计算熵的伪代码:
for 实例 in dataSet:
建立key值为样本标签值,value值为标签值出现的次数的字典
通过每个实例更新该字典
for key in 字典:
计算每个标签出现的频率
更新香农熵
返回香农熵
代码如下:
def calcShannonEnt(dataSet):
numEntries = len(dataSet) # 数据集一共有多少个实例
labelCounts = {
} # 定义一个字典,key为标签的可能值,value为该可能值的个数
for featVec in dataSet:
currentLabel = featVec[-1]
if currentLabel not in labelCounts.keys(): # 如果现在字典中没有该可能值,则初始化其value为0
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0 # 初始化香农熵为0
for key in labelCounts:
prob = float(labelCounts[key])/numEntries
shannonEnt -= prob * log(prob, 2) # 计算香农熵
return shannonEnt
划分数据集
求得数据集的熵之后,我们就要通过特征的划分,来降低数据集的熵,这个降低的值,就是信息增益。信息增益的计算公式为(这个公式是我为了解释清楚而自己定义的,没有任何来历的):

其中n为该特征的可能值个数(即数据集被该特征划分成了多少块),Pi为第i块数据子集中的实例占整个数据集的比例,Hi为第i块数据子集的信息熵。所以,我们之前所要找的最好的划分方式,就是用信息增益最大的特征来进行划分(这里假设我们已经找到这个特征啦)。
划分数据集的伪代码如下:
# 函数参数为数据集dataSet,划分数据集的特征A, 划分后这一块数据子集对应的特征值V
创建空列表r
for 实例 in dataSet:
if 该实例的特征A的值为V:
将该实例的特征A去掉后添加到r中
返回r
代码如下:
def splitDataSet(dataSet, axis, value): # 输入参数分别为:待划分的数据集,划分数据集的特征,划分后这一块数据子集对应的特征值
retDataSet = [] # 建立新的list对象,存储划分后的数据子集
for featVec in dataSet: # 遍历数据集,一旦发现符合要求的实例,则将其元素抽取,并添加到新建的列表中
if featVec[axis] == value:
reducedFeatVec = featVec

本文以易于理解的方式介绍了决策树的基本概念和实现,包括决策树的构建过程,熵和信息增益的计算,并给出了用伪代码表示的决策树划分数据集和构建过程。文章以一个简单的例子说明如何利用决策树进行分类,适合初学者入门。
&spm=1001.2101.3001.5002&articleId=104215072&d=1&t=3&u=0e45534697ce42b08ed48b32b7a78cc0)
8223

被折叠的 条评论
为什么被折叠?



