赞
踩
决策树是机器学习中属于监督类算法,有ID3,C4.5,C5.0,CART(Classification and Regression Tree),CHAID(CHi-squared Automatic Interaction Detection),决策树是一种树形结构,每个内部节点表示一种属性判断,每个分支表示一种判断结果,每个叶子节点(终端节点)表示一种分类结果。
下图就是一种流程图形式的决策树:
决策树优点 | 决策树缺点 |
---|---|
计算复杂度不高,输出结果容易理解,对中间值缺失不敏感,可以处理不相关特征数据 | 可能会产生过度匹配问题 |
标称型:标称型目标变量的结果只在有限目标集中取值,比如真与假(标称型目标变量主要用于分类)
数值型:数值型目标变量则可以从无限的数值集合中取值,如0.555,666.666等 (数值型目标变量主要用于回归分析)
CreateBranch():
检查数据集中的每个子项是否属于同一分类:
If so return 类标签
Else
寻找划分数据集的最好特征
划分数据集
创建分支节点
for 每个划分的子集
调用函数CreateBranch并增加返回结果到分支节点中
return 分支节点
决策树的一般流程 |
---|
1.收集数据:可以使用任何方法 |
2.准备数据:树构造算法只适用于标称型数据,因此数值型数据必须离散化 |
3.分析数据:可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期 |
4.训练算法:构造树的数据结构 |
5.测试算法:使用经验树计算错误率 |
6.使用算法:此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义。 |
划分数据的大原则是:将无序的数据变得更加有序。
在划分数据之前之后的信息发生变化成为信息增益,知道如何计算信息增益,我们就可以计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就算最好的选择。
下面我们需要知道两个专有名词:信息增益(information gain)和熵(entropy),熵定义为信息的期望值,那么信息的定义为:
l
(
x
i
)
=
−
l
o
g
2
p
(
x
i
)
l(x_i) = -log_2p(x_i)
l(xi)=−log2p(xi)
其中
p
(
x
i
)
p(x_i)
p(xi)是选择该分类的概率。
为了计算熵,我们需要计算所有可能值包含的信息期望值,通过下面的公式得到:
E
n
t
(
D
)
=
−
∑
i
=
1
n
p
(
x
i
)
l
o
g
2
p
(
x
i
)
Ent(D) = -\sum_{i=1}^np(x_i)log_2p(x_i)
Ent(D)=−i=1∑np(xi)log2p(xi)
Ent(D)的值越小,说明其纯度越高;计算信息熵时约定:若 p = 0 , 则 p l o g 2 p = 0 , H 最 小 值 为 0 , 最 大 值 为 l o g 2 n . p=0,则plog_2p=0,H最小值为0,最大值为log_2n. p=0,则plog2p=0,H最小值为0,最大值为log2n.
信息增益定义:
假
定
离
散
属
性
a
有
V
个
可
能
的
取
值
{
a
1
,
a
2
,
.
.
.
,
a
V
}
,
若
使
用
a
来
对
样
本
集
D
进
行
划
分
,
则
会
产
生
V
个
分
支
节
点
,
其
中
第
v
个
分
支
节
点
包
含
了
D
中
所
有
在
属
性
a
上
取
值
为
a
v
的
样
本
,
记
为
D
v
.
我
们
可
根
据
熵
的
公
式
计
算
出
D
v
的
信
息
熵
,
再
考
虑
到
不
同
分
支
结
点
所
包
含
的
样
本
数
不
同
,
给
分
支
结
点
赋
予
权
重
∣
D
v
∣
/
∣
D
∣
,
即
样
本
越
多
的
分
支
结
点
的
影
响
越
大
,
于
是
可
计
算
出
用
属
性
a
对
样
本
集
D
进
行
划
分
所
获
得
的
信
息
增
益
(
i
n
f
o
r
m
a
t
i
o
n
g
a
i
n
)
:
G
a
i
n
(
D
,
a
)
=
E
n
t
(
D
)
−
∑
v
=
1
V
∣
D
v
∣
∣
D
∣
E
n
t
(
D
v
)
.
假定离散属性a有V个可能的取值\{a^1,a^2,...,a^V\},若使用a来对样本集D进行划分,则会产生V个分支节点,\\其中第v个分支节点包含了D中所有在属性a上取值为a^v的样本,记为D^v.我们可根据熵的公式\\计算出D^v的信息熵,再考虑到不同分支结点所包含的样本数不同,给分支结点赋予权重|D^v|/|D|,\\即样本越多的分支结点的影响越大,于是可计算出用属性a对样本集D进行划分所获得的\\信息增益(information gain): \\ Gain(D,a) =Ent(D) - \sum_{v=1}^V\frac{|D^v|}{|D|}Ent(D^v).
假定离散属性a有V个可能的取值{a1,a2,...,aV},若使用a来对样本集D进行划分,则会产生V个分支节点,其中第v个分支节点包含了D中所有在属性a上取值为av的样本,记为Dv.我们可根据熵的公式计算出Dv的信息熵,再考虑到不同分支结点所包含的样本数不同,给分支结点赋予权重∣Dv∣/∣D∣,即样本越多的分支结点的影响越大,于是可计算出用属性a对样本集D进行划分所获得的信息增益(informationgain):Gain(D,a)=Ent(D)−v=1∑V∣D∣∣Dv∣Ent(Dv).
一般而言,信息增益越大,则意味着使用属性a来划分所获得的”纯度提升"越大。即选则属性
a
∗
=
a
r
g
a
∈
A
m
a
x
G
a
i
n
(
D
,
a
)
a_* = arg_{a\in A}max \,Gain(D,a)
a∗=arga∈AmaxGain(D,a)
例子:下面是海洋生物数据
不浮出水面是否可以生存 | 是否有脚蹼 | 属于鱼类 | |
---|---|---|---|
1 | 是 | 是 | 是 |
2 | 是 | 是 | 是 |
3 | 是 | 否 | 否 |
4 | 否 | 是 | 否 |
5 | 否 | 是 | 否 |
上面包括5个海洋动物,特征包括:不浮出水面是否可以生存,是否有脚蹼。分成两类,鱼类和非鱼类,现在我们想要决定依据第一个特征还是第二个特征划分数据
在决策树开始时,显然只有两种结果,属于鱼类或不属于鱼类,|y| = 2.
正
例
p
1
=
2
5
,
反
例
p
2
=
3
5
正例p_1=\frac{2}{5},反例p_2=\frac{3}{5}
正例p1=52,反例p2=53
E
n
t
(
D
)
=
−
∑
k
=
1
2
p
k
l
o
g
2
p
k
=
−
(
2
5
l
o
g
2
2
5
+
3
5
l
o
g
2
3
5
)
=
0.97095
Ent(D) = -\sum_{k=1}^2p_klog_2p_k = -(\frac{2}{5}log_2\frac{2}{5}+\frac{3}{5}log_2\frac{3}{5})=0.97095
Ent(D)=−k=1∑2pklog2pk=−(52log252+53log253)=0.97095
如
果
我
们
以
不
浮
出
水
面
是
否
可
以
生
存
这
个
属
性
来
划
分
,
那
么
可
知
该
属
性
正
例
占
比
3
5
,
反
例
2
5
,
正
例
中
属
于
鱼
类
为
2
3
,
不
属
于
鱼
类
为
1
3
,
反
例
中
属
于
鱼
类
为
0
,
不
属
于
鱼
类
为
1
,
那
么
有
E
n
t
(
D
1
)
=
−
(
2
3
l
o
g
2
2
3
+
1
3
l
o
g
2
1
3
)
=
0.91829
;
E
n
t
(
D
2
)
=
0
;
G
a
i
n
(
D
,
是
否
浮
出
水
面
)
=
E
n
t
(
D
)
−
∑
v
=
1
2
∣
D
v
∣
∣
D
∣
E
n
t
(
D
v
)
=
0.97095
−
(
3
5
∗
0.91829
+
2
5
∗
0
)
=
0.419976
如果我们以不浮出水面是否可以生存这个属性来划分,那么可知该属性正例占比\frac{3}{5},反例\frac{2}{5},\\正例中属于鱼类为\frac{2}{3},\\不属于鱼类为\frac{1}{3},反例中属于鱼类为0,不属于鱼类为1,那么有\\\ Ent(D_1)=-(\frac{2}{3}log_2\frac{2}{3}+\frac{1}{3}log_2\frac{1}{3}) =0.91829 ; \\\ Ent(D_2) = 0;\\\ Gain(D,是否浮出水面) = Ent(D) - \sum_{v=1}^2\frac{|D^v|}{|D|}Ent(D^v)\\\ =0.97095-(\frac{3}{5}*0.91829+\frac{2}{5}*0)\\\ =0.419976
如果我们以不浮出水面是否可以生存这个属性来划分,那么可知该属性正例占比53,反例52,正例中属于鱼类为32,不属于鱼类为31,反例中属于鱼类为0,不属于鱼类为1,那么有 Ent(D1)=−(32log232+31log231)=0.91829; Ent(D2)=0; Gain(D,是否浮出水面)=Ent(D)−v=1∑2∣D∣∣Dv∣Ent(Dv) =0.97095−(53∗0.91829+52∗0) =0.419976
类似的我们可以计算出第二个特征是否有脚蹼的信息增益:
G
a
i
n
(
D
,
是
否
有
脚
蹼
)
=
0.17095
Gain(D,是否有脚蹼) = 0.17095
Gain(D,是否有脚蹼)=0.17095
很明显,第一个特征的信息增益最大,所以第一个分支以第一个属性作为结点,第二个分支结点以第二个属性为结点。
根据上面的列表创建对应的数据如下:
def createDataSet():
"""
创建数据集
:return:数据集
"""
dataSet = [[1, 1, 'yes'],
[1, 1, 'yes'],
[1, 0, 'no'],
[0, 1, 'no'],
[0, 1, 'no']
]
labels = ['no surfacing', 'flippers']
return dataSet, labels
def calShannonEnt(dataSet): """ 计算给定数据集的香农熵 公式: H = -Σ(n,i=1)p(xi)log2p(xi),其中p(xi)是选择该分类的概率 :param dataSet: 数据集 :return: 返回熵 """ numEntries = len(dataSet)#求数据长度 labelCounts = {}#用字典来统计标签 for featVec in dataSet: currentLabel = featVec[-1] #标签放在最后一个 if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0 labelCounts[currentLabel] += 1 shannonEnt = 0.0 for key in labelCounts: prob = float(labelCounts[key])/numEntries shannonEnt -= prob * log(prob,2) return shannonEnt
def chooseBestFeatureToSplit(dataSet): """ 选择最好的数据集划分方式 :param dataSet:数据集 :return:返回最佳分割位置 """ #计算属性长度 numFeatures = len(dataSet[0])-1 #未划分前的熵值 baseEntropy = calShannonEnt(dataSet) bestInfoGain = 0.0; bestFeature = -1 for i in range(numFeatures): #获取当前属性所有取值 featList = [example[i] for example in dataSet] #去掉属性中重复的取值 uniqueVals = set(featList) newEntropy = 0.0 for value in uniqueVals: #求得每种划分的信息熵 subDataSet = spliteDataSet(dataSet, i, value) prob = len(subDataSet)/float(len(dataSet)) newEntropy += prob * calShannonEnt(subDataSet) infoGain = baseEntropy - newEntropy if (infoGain > bestInfoGain): bestInfoGain = infoGain bestFeature = i return bestFeature
def creatTree(dataSet,labels): """ 创建树的函数代码 :param dataSet:数据集合 :param labels:特征值集合 :return:一棵决策树 """ #获取属性取值集合 classList = [example[-1] for example in dataSet] print("classList:") print(classList) print("labels:") print(labels) #当前列表中都属于同一个值,类别完全相同停止继续划分 if classList.count(classList[0]) == len(classList): print("all items equals:") print(classList) return classList[0] if len(dataSet[0]) == 1: print("dataSet:") print(dataSet) print("dataSet[0]:") print(dataSet[0]) return majorityCnt(classList) bestFeat = chooseBestFeatureToSplit(dataSet) bestFeatLabel = labels[bestFeat] myTree = {bestFeatLabel:{}} del(labels[bestFeat]) featValues = [example[bestFeat] for example in dataSet] uniqueVals = set(featValues) for value in uniqueVals: subLabels = labels[:] #复制类标签 myTree[bestFeatLabel][value] = creatTree(spliteDataSet(dataSet, bestFeat, value), subLabels) return myTree
#创建数据集
mydat, labels = createDataSet()
#复制一份,防止改变该变量
labelscopy = labels.copy()
#创建决策树 实际上是一个字典集合
myTree = creatTree(mydat, labels)
print(myTree)
#导入绘图类 decision_graphic_tree.py
import decision_graphic_tree
#根据创建的决策树进行绘图
decision_graphic_tree.createPlot(myTree)
其中绘制属性图采用了Matplotlib注解工具annotations来实现,具体实现在decision_graphic_tree.py里面。
详细代码请参考本人github。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。