前面我们讲到了
I
D
3
ID3
ID3算法,也知道了如何选择决策树分裂的属性,但是有人发现
I
D
3
ID3
ID3算法不能对连续的数据进行处理,只能将连续的数据离散化处理,同时
I
D
3
ID3
ID3算法并没有做剪枝处理,导致决策树可能会过于复杂导致过拟合。于是在这个基础上衍生出了
C
4.5
C4.5
C4.5算法。
C
4.5
C4.5
C4.5针对
I
D
3
ID3
ID3主要做出了以下几种优化:
1. 通过信息增益率选择分裂属性
2. 能够处理离散型和连续型的属性类型
3. 构造决策树之后进行剪枝操作
4. 能够处理具有缺失属性值的训练数据
-
信息增益率
C 4.5 C4.5 C4.5算法使用信息增益率来进行特征的选择,克服了信息增益选择特征时偏向于特征值个数较多的不足。信息增益率的定义如下: G ain R a t i o ( S , A ) = G a i n ( S , A ) S p l i t I n f o ( S , A ) G{\text{ain}}Ratio(S,A) = \frac{{Gain(S,A)}}{{SplitInfo(S,A)}} GainRatio(S,A)=SplitInfo(S,A)Gain(S,A)
其中 G a i n ( S , A ) Gain(S,A) Gain(S,A)就是前面 I D 3 ID3 ID3算法中提到的信息增益, S p l i t I n f o ( S , A ) SplitInfo(S,A) SplitInfo(S,A)表示特征 A A A在样本集 S S S中的广度和均匀度,其定义为: S p l i t I n f o ( S , A ) = − ∑ i = 1 n ∣ S i ∣ ∣ S ∣ log 2 ( ∣ S ∣ ∣ S i ∣ ) SplitInfo(S,A) = - \sum\limits_{i = 1}^n {\frac{{|{S_i}|}}{{|S|}}{{\log }_2}(\frac{{|S|}}{{|{S_i}|}})} SplitInfo(S,A)=−i=1∑n∣S∣∣Si∣log2(∣Si∣∣S∣) 其中 S i S_i Si到 S n S_n Sn是 A A A的 n n n个不同子集 -
实例分析
还是使用 I D 3 ID3 ID3算法中的例子来分析 C 4.5 C4.5 C4.5算法
由上一章得到
G
a
i
n
(
S
,
o
u
t
l
o
o
k
)
=
1
−
0.5528
=
0.4472
Gain(S,outlook) = 1 - 0.5528= 0.4472
Gain(S,outlook)=1−0.5528=0.4472,而
o
u
t
l
o
o
k
outlook
outlook中有
r
a
i
n
y
rainy
rainy有8个,
o
v
e
r
c
a
s
t
overcast
overcast 9个,
s
u
n
n
y
sunny
sunny 7个,所以:
S
p
l
i
t
I
n
f
o
(
S
,
o
u
t
l
o
o
k
)
=
−
(
8
24
log
2
8
24
+
9
24
log
2
9
24
+
7
24
log
2
7
24
)
=
1.5774
SplitInfo(S,outlook) = - (\frac{8}{{24}}{\log _2}\frac{8}{{24}} + \frac{9}{{24}}{\log _2}\frac{9}{{24}} + \frac{7}{{24}}{\log _2}\frac{7}{{24}}) = 1.5774
SplitInfo(S,outlook)=−(248log2248+249log2249+247log2247)=1.5774
计算出
o
u
t
l
o
o
k
outlook
outlook的信息增益率为:
G
ain
R
a
t
i
o
(
S
,
o
u
t
l
o
o
k
)
=
0.4772
1.5774
=
0.3025
G{\text{ain}}Ratio(S,outlook) = \frac{{0.4772}}{{1.5774}} = 0.3025
GainRatio(S,outlook)=1.57740.4772=0.3025
同理:
S
p
l
i
t
I
n
f
o
(
S
,
t
e
m
)
=
−
(
5
24
log
2
5
24
+
10
24
log
2
10
24
+
9
24
log
2
9
24
)
=
1.5284
SplitInfo(S,tem) = - (\frac{5}{{24}}{\log _2}\frac{5}{{24}} + \frac{10}{{24}}{\log _2}\frac{10}{{24}} + \frac{9}{{24}}{\log _2}\frac{9}{{24}}) = 1.5284
SplitInfo(S,tem)=−(245log2245+2410log22410+249log2249)=1.5284
G
ain
R
a
t
i
o
(
S
,
t
e
m
)
=
0.1107
1.5284
=
0.0724
G{\text{ain}}Ratio(S,tem) = \frac{{0.1107}}{{1.5284}} = 0.0724
GainRatio(S,tem)=1.52840.1107=0.0724
S
p
l
i
t
I
n
f
o
(
S
,
h
u
m
)
=
−
2
(
12
24
log
2
12
24
)
=
1
SplitInfo(S,hum) = - 2(\frac{12}{{24}}{\log _2}\frac{12}{{24}}) = 1
SplitInfo(S,hum)=−2(2412log22412)=1
G
ain
R
a
t
i
o
(
S
,
h
u
m
)
=
0.0817
1
=
0.0817
G{\text{ain}}Ratio(S,hum) = \frac{{0.0817}}{{1}} = 0.0817
GainRatio(S,hum)=10.0817=0.0817
S
p
l
i
t
I
n
f
o
(
S
,
w
i
n
d
y
)
=
−
(
8
24
log
2
8
24
+
10
24
log
2
10
24
+
6
24
log
2
6
24
)
=
1.5546
SplitInfo(S,windy) = - (\frac{8}{{24}}{\log _2}\frac{8}{{24}} + \frac{10}{{24}}{\log _2}\frac{10}{{24}} + \frac{6}{{24}}{\log _2}\frac{6}{{24}}) = 1.5546
SplitInfo(S,windy)=−(248log2248+2410log22410+246log2246)=1.5546
G
ain
R
a
t
i
o
(
S
,
w
i
n
d
y
)
=
0
1.5546
=
0
G{\text{ain}}Ratio(S,windy) = \frac{{0}}{{1.5546}} = 0
GainRatio(S,windy)=1.55460=0
因为 o u t l o o k outlook outlook的信息增益率最高,选择 o u t l o o k outlook outlook为分裂属性,然后一直递归。
C 4.5 C4.5 C4.5是 I D 3 ID3 ID3的衍生,所以实现代码跟 I D 3 ID3 ID3也类似,只需要修改信息增益计算的函数 c a l c S h a n n o n E n t calcShannonEnt calcShannonEnt和最优特征选择函数 c h o o s e B e s t F e a t u r e T o S p l i t chooseBestFeatureToSplit chooseBestFeatureToSplit
- 修改 d e f c a l c S h a n n o n E n t ( d a t a S e t ) : def\ calcShannonEnt(dataSet): def calcShannonEnt(dataSet):函数,增加一个特征选择的参数
def calcShannonEnt(dataSet, feat): #feat为特征位置
numEntries = len(dataSet)
labelCounts = {}
for feaVec in dataSet:
currentLabel = feaVec[feat] #选择特征
if currentLabel not in labelCounts:
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
- 修改 d e f c h o o s e B e s t F e a t u r e T o S p l i t ( d a t a S e t ) : def\ chooseBestFeatureToSplit(dataSet): def chooseBestFeatureToSplit(dataSet):增加当前特征的熵 I V IV IV计算
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1
baseEntropy = calcShannonEnt(dataSet, -1)
bestInfoGainRate = 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 = splitDataSet(dataSet, i, value)
prob = len(subDataSet) / float(len(dataSet))
newEntropy += prob *calcShannonEnt(subDataSet, -1) #calc conditional entropy
infoGain = baseEntropy - newEntropy
iv = calcShannonEnt(dataSet, i)
if(iv == 0):
continue
infoGainRate = infoGain / iv
if infoGainRate > bestInfoGainRate:
bestInfoGainRate = infoGainRate
bestFeature = i
return bestFeature
最终生成的决策树如下:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e415bc43fd1f64cb9cd6cb2874e768ec.png)
-
连续型数据处理
当属性类型为离散型,无须对数据进行离散化处理;当属性类型为连续型,则需要对数据进行离散化处理(连续型属性的离散化处理)。
核心思想:
1. 将属性 A A A的 N N N个属性值按照升序排列
2. 二分法将属性 A A A的所有属性分成两部分(共有 N − 1 N-1 N−1种划分方法,二分的阈值为相邻两个属性值的中间值)
3. 计算每种划分方法对应的信息增益,选取信息增益最大的划分方法的阈值作为属性 A A A二分的阈值 -
缺失值处理
在某些情况下,可供使用的数据可能缺少某些属性的值。处理策略:
1. 赋给该属性的最常见值
2. 另外一种更复杂的策略是为Fi的每个可能值赋予一个概率。例如,给定一个布尔属性Fi,如果结点t包含6个已知Fi_v=1和4个Fi_v=0的实例,那么Fi_v=1的概率是0.6,而Fi_v=0的概率是0.4。于是,实例x的60%被分配到Fi_v=1的分支,40%被分配到另一个分支。这些片断样例(fractional examples)的目的是计算信息增益,另外,如果有第二个缺少值的属性必须被测试,这些样例可以在后继的树分支中被进一步细分。
3. 丢弃这些样本 -
剪枝
前面的算法生成的决策树非常的详细而庞大,每个属性都被详细地加以考虑,决策树的树叶节点所覆盖的训练样本都是纯的。因此用这个决策树来对训练样本进行分类的话,对于训练样本而言,这个树表现堪称完美,它可以100%正确得对训练样本集中的样本进行分类,因为决策树本身就是100%完美拟合训练样本的产物。但是这会带来一个问题,如果训练样本中包含了一些错误,按照前面的算法,这些错误也会100%一点不留得被决策树学习了,这种方式被我们称为过拟合”。前人很早就发现了这个问题,于是提出了剪枝的概念。
通常剪枝方法都是使用统计度量,剪去最不可靠的分枝。一般分两种方法:先剪枝和后剪枝。
先剪枝方法中通过提前停止树的构造而对树剪枝。一旦停止,这个节点就变成树叶,该树叶可能取它持有的子集最频繁的类作为自己的类。
先剪枝有很多方法:
1. 当决策树达到一定的高度就停止决策树的生长
2. 到达此节点的实例具有相同的特征向量,而不必一定属于同一类,也可以停止生长
3. 到达此节点的实例个数小于某个阈值的时候也可以停止树的生长,不足之处是不能处理那些数据量比较小的特殊情况
4. 计算每次扩展对系统性能的增益,如果小于某个阈值就可以让它停止生长。先剪枝有个缺点就是视野效果问题,也就是说在相同的标准下,也许当前扩展不能满足要求,但更进一步扩展又能满足要求。这样会过早停止决策树的生长
后剪枝由完全成长的树剪去子树而形成。通过删除节点的分枝并用树叶来替换它。树叶一般用子树中最频繁的类别来标记。
后剪枝主要有以下几种方法,详细说明请看剪枝算法介绍:
1. 错误率降低剪枝( R E P REP REP)
2. 悲观错误剪枝( P E P PEP PEP)
2. 代价复杂度剪枝( C C P CCP CCP)
C 4.5 C4.5 C4.5采用悲观剪枝法( P E P PEP PEP),它使用训练集生成决策树又用它来进行剪枝,不需要独立的剪枝集,具体的分析我这里就不讲解了,我觉得剪枝算法这篇博文讲的非常详细,大家如果有兴趣,可以了解一下。
到这里我对C4.5算法的理解就结束了,希望对您有所帮助,本人能力有限,如有纰漏请轻喷,不吝指教。