前面我们讲到了
算法,也知道了如何选择决策树分裂的属性,但是有人发现
算法不能对连续的数据进行处理,只能将连续的数据离散化处理,同时
算法并没有做剪枝处理,导致决策树可能会过于复杂导致过拟合。于是在这个基础上衍生出了
算法。
针对
主要做出了以下几种优化:
1. 通过信息增益率选择分裂属性
2. 能够处理离散型和连续型的属性类型
3. 构造决策树之后进行剪枝操作
4. 能够处理具有缺失属性值的训练数据
-
信息增益率
算法使用信息增益率来进行特征的选择,克服了信息增益选择特征时偏向于特征值个数较多的不足。信息增益率的定义如下:
其中 就是前面 算法中提到的信息增益, 表示特征 在样本集 中的广度和均匀度,其定义为: 其中 到 是 的 个不同子集 -
实例分析
还是使用 算法中的例子来分析 算法
由上一章得到
,而
中有
有8个,
9个,
7个,所以:
计算出
的信息增益率为:
同理:
因为 的信息增益率最高,选择 为分裂属性,然后一直递归。
是 的衍生,所以实现代码跟 也类似,只需要修改信息增益计算的函数 和最优特征选择函数
- 修改 函数,增加一个特征选择的参数
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
- 修改 增加当前特征的熵 计算
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
最终生成的决策树如下:
-
连续型数据处理
当属性类型为离散型,无须对数据进行离散化处理;当属性类型为连续型,则需要对数据进行离散化处理(连续型属性的离散化处理)。
核心思想:
1. 将属性 的 个属性值按照升序排列
2. 二分法将属性 的所有属性分成两部分(共有 种划分方法,二分的阈值为相邻两个属性值的中间值)
3. 计算每种划分方法对应的信息增益,选取信息增益最大的划分方法的阈值作为属性 二分的阈值 -
缺失值处理
在某些情况下,可供使用的数据可能缺少某些属性的值。处理策略:
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. 错误率降低剪枝( )
2. 悲观错误剪枝( )
2. 代价复杂度剪枝( )
采用悲观剪枝法( ),它使用训练集生成决策树又用它来进行剪枝,不需要独立的剪枝集,具体的分析我这里就不讲解了,我觉得剪枝算法这篇博文讲的非常详细,大家如果有兴趣,可以了解一下。
到这里我对C4.5算法的理解就结束了,希望对您有所帮助,本人能力有限,如有纰漏请轻喷,不吝指教。