ID3具有一定的局限性,即信息增益倾向于选择取值比较多的特征(特征越多,条件熵(特征划分后的类别变量的熵)越小,信息增量就越大),C4.5通过选择最大的信息增益率 gain ratio 来选择节点可以解决该问题。并且C4.5算法可以处理连续和有缺失值的数据。

C4.5与ID3在实现过程中,不同之处在于将计算信息增益的函数改为计算信息增益率。

譬如,对于上一个例子中的湿度这一项的取值改为:

Day

Outlook

Temperature

Humidity

Wind

PlayTennis

1

Sunny

Hot

85

Weak

No

2

Sunny

Hot

90

Strong

No

3

Overcast

Hot

78

Weak

Yes

4

Rain

Mild

96

Weak

Yes

5

Rain

Cool

80

Weak

Yes

6

Rain

Cool

70

Strong

No

7

Overcast

Cool

65

Strong

Yes

8

Sunny

Mild

95

Weak

No

9

Sunny

Cool

70

Weak

Yes

10

Rain

Mild

80

Weak

Yes

11

Sunny

Mild

70

Strong

Yes

12

Overcast

Mild

90

Strong

Yes

13

Overcast

Hot

75

Weak

Yes

14

Rain

Mild

80

Strong

No

Gain(Wind) = Entropy(S) – (8/14)* Entrogy(weak)-(6/14)* Entrogy(strong) = 0.048

weak = 8;Strong = 6

Feature(Wind) = -8/14*log(8/14)-6/14*log(6/14) = 0.9852

RatioGain(Wind) = Gain(Wind)/Feature (Wind) = 0.0487

同理:RatioGain(Outlook) = 0.247/1.577 = 0.1566

RatioGain(Temperature)= 0.029/1.556 = 0.018

其中,对于连续值的计算:

1.      对特征的取值进行升序排序

2.      两个特征取值之间的中点作为可能的分裂点,将数据集分成两部分,计算每个可能的分裂点的信息增益(InforGain)。优化算法就是只计算分类属性发生改变的那些特征取值。

3.      选择修正后信息增益(InforGain)最大的分裂点作为该特征的最佳分裂点

4.      计算最佳分裂点的信息增益率(Gain Ratio)作为特征的Gain Ratio。注意,此处需对最佳分裂点的信息增益进行修正:减去log2(N-1)/|D|(N是连续特征的取值个数,D是训练数据数目,此修正的原因在于:当离散属性和连续属性并存时,C4.5算法倾向于选择连续特征做最佳树分裂点)

故,划分为:{ 65、70、75、78、80、85、90、95、96 } 这几个特征。

65

70

75

78

80

85

90

95

96

>

>

>

>

>

>

>

>

>

Yes

1

8

3

6

4

5

5

4

7

2

7

2

8

1

8

1

9

0

No

0

5

1

4

1

4

1

4

2

3

3

2

4

1

5

0

5

0

Entropy

0

0.961

0.811

0.971

0.722

0.991

0.65

1

0.764

0.971

0.881

1

0.918

1

0.961

0

0.94

0

Gain

0.048

0.015

0.045

0.090

0.102

0.025

0.011

0.048

0

此时,可以看到当特征小于等于80时,信息增益最大,选取该取值区间作为湿度属性的信息增益。

即Gain(Humidity) = 0.102

Feature(Humidity) = -9/14*log(9/14) - 5/14*log(5/14) = 0.940(两个分支,大于80的和小于等于80的)

RatioGain(Humidity) = 0.102/0.940 = 1.085

//------------------------------------------------

对于ID3算法局限性的理解:

X = [['sunny',    'hot',   'h_85',   'weak'],
['sunny', 'hot', 'h_90', 'strong'],
['overcast', 'hot', 'h_78', 'weak'],
['rain', 'mild', 'h_96', 'weak'],
['rain', 'cool', 'h_80', 'weak'],
['rain', 'cool', 'h_70', 'strong'],
['overcast', 'cool', 'h_65', 'strong'],
['sunny', 'mild', 'h_95', 'weak'],
['sunny', 'cool', 'h_70', 'weak'],
['rain', 'mild', 'h_80', 'weak'],
['sunny', 'mild', 'h_70', 'strong'],
['overcast', 'mild', 'h_90', 'strong'],
['overcast', 'hot', 'h_75', 'weak'],
['rain', 'mild', 'h_80', 'strong'],
]

  对于ID3算法的输入改为,可以看到生成的决策树为:

可以看到,此时就会出现过拟合的现象。

而采用信息增益率作为判决条件的话:

estimator = Id3Estimator(gain_ratio=1)

  获得的决策树为:

因此,对于使用信息增益作为分类准则和使用信息增益率的区别如上所示。

//-----------------------------------

对于处理数值的理解:

解读python的第三方库,ID3模块(decision-tree-id3

在其中id3.py模块中:

Id3Estimator类的fit函数中

for i in range(self.n_features):
if check_input and check_numerical_array(X_[:, i]):
self.is_numerical[i] = True
X_tmp[:, i] = X_[:, i]
else:
X_tmp[:, i] = self.X_encoders[i].fit_transform(X_[:, i])

  这里会判断一下传递的特征是名字还是数字,判断的方法在checks.py中:

def check_numerical_array(array):
""" Check if all values in a 1d array are numerical. Raises error if array
is more than 1d. Parameters
----------
array : nparray
containing the class names Returns
-------
result : bool
True if all values in array are numerical, otherwise false
"""
try:
if array.ndim > 1:
raise ArithmeticError("Found array with dim {}. Expected = 1."
.format(array.ndim))
array.astype(np.float64)
return True
except ValueError:
return False

  此处会做一个类型转换,如果输入的是数字、字符串形式的数字都会被转为float类型。

(此次我觉得不太妥当,字符串形式的数字不应该转化为数字,说不定人家就是想这样输入作为feature呢,譬如我上面的输入数字的开头还要加一个 ‘h_’)

当特征为数字的时候计算方法在splitter.py文件中:

def _info_numerical(self, x, y):
""" Info for numerical feature feature_values
sort values then find the best split value Parameters
----------
x : np.array of shape [n remaining examples]
containing feature values
y : np.array of shape [n remaining examples]
containing relevent class Returns
-------
: float
information for remaining examples given feature
: float
pivot used set1 < pivot <= set2
"""
n = x.size
sorted_idx = np.argsort(x, kind='quicksort')
sorted_y = np.take(y, sorted_idx, axis=0)
sorted_x = np.take(x, sorted_idx, axis=0)
min_info = float('inf')
min_info_pivot = 0
min_attribute_counts = np.empty(2)
for i in range(1, n):
if sorted_x[i - 1] != sorted_x[i]:
tmp_info = i * self._entropy(sorted_y[0: i]) + \
(n - i) * self._entropy(sorted_y[i:])
if tmp_info < min_info:
min_attribute_counts[SplitRecord.LESS] = i
min_attribute_counts[SplitRecord.GREATER] = n - i
min_info = tmp_info
min_info_pivot = (sorted_x[i - 1] + sorted_x[i]) / 2.0
return CalcRecord(CalcRecord.NUM,
min_info * np.true_divide(1, n),
pivot=min_info_pivot,
attribute_counts=min_attribute_counts)

  

可以看到,其计算过程和上述对于数值的计算过程一样,其min_info为选取的最小的分类后的信息熵,为了得到最大的信息增益。

而对于是否使用信息增益率的判断在splitter.py文件中:

def _is_better(self, calc_record1, calc_record2):
"""Compares CalcRecords using gain ratio if present otherwise
using the information. Parameters
----------
calc_record1 : CalcRecord
calc_record2 : CalcRecord Returns
-------
: bool
if calc_record1 < calc_record2
"""
if calc_record1 is None:
return True
if calc_record2 is None:
return False
if self.gain_ratio:
if calc_record1.gain_ratio is None:
calc_record1.gain_ratio = self._gain_ratio(calc_record1)
if calc_record2.gain_ratio is None:
calc_record2.gain_ratio = self._gain_ratio(calc_record2)
if self._is_close(calc_record1.gain_ratio,
calc_record2.gain_ratio):
return calc_record1.info > calc_record2.info
else:
return calc_record1.gain_ratio < calc_record2.gain_ratio
else:
return calc_record1.info > calc_record2.info

  

故,对于C4.5算法,同样可以使用ID3模块,只不过设置参数:gain_ratio=True即可。

得到的决策树为:

下面我们验证在sunny情况下,humidity的划分便准是否正确:

Day

Outlook

Temperature

Humidity

Wind

PlayTennis

1

Sunny

Hot

85

Weak

No

2

Sunny

Hot

90

Strong

No

8

Sunny

Mild

95

Weak

No

9

Sunny

Cool

70

Weak

Yes

11

Sunny

Mild

70

Strong

Yes

首先计算humidity:

70

85

90

95

>

>

>

>

Yes

2

0

2

0

2

0

2

0

No

0

3

1

2

2

1

3

0

Entropy

0

0

0.756

0

0.846

0

0.971

0

Gain

0.971

0.517

0.294

0

Gain(humidity) = 0.971

Feature(humidity) = -2/5*log(-2/5) - 3/5*log(3/5) = 0.971(分两组,小于等于70的有2个数据,大于70的有3个数据)

RatioGain(humidity) = 1

Gain(Temperature) = 0.971 -  (-log(0.5) * 2/5) = 0.571

Feature(Temperature) = -2/5*log(-2/5)*2 - 1/5*log(1/5) = 1.522(分三组,分别有2、2、1个数据)

RatioGain(Temperature) = 0.375

Gain(Wind) = 0.971 - (3/5*(-1/3*log(1/3)-2/3*log(2/3)) + 2/5( -1/2*log(1/2)-1/2*log(1/2)))= 0.02

Feature(Wind) = 0.971

RatioGain(Wind) = 0.02

因此,程序得到的结果是对的。

决策树算法(C4.5)的更多相关文章

  1. 机器学习回顾篇(7):决策树算法(ID3、C4.5)

    .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px so ...

  2. R_Studio(决策树算法)鸢尾花卉数据集Iris是一类多重变量分析的数据集【精】

    鸢尾花卉数据集Iris是一类多重变量分析的数据集 通过花萼长度,花萼宽度,花瓣长度,花瓣宽度4个属性预测鸢尾花卉属于(Setosa,Versicolour,Virginica)三个种类中的哪一类 针对 ...

  3. [转]机器学习——C4.5 决策树算法学习

    1. 算法背景介绍 分类树(决策树)是一种十分常用的分类方法.它是一种监管学习,所谓监管学习说白了很简单,就是给定一堆样本,每个样本都有一组属性和一个类别,这些类别是事先确定的,那么通过学习得到一个分 ...

  4. 决策树算法原理(ID3,C4.5)

    决策树算法原理(CART分类树) CART回归树 决策树的剪枝 决策树可以作为分类算法,也可以作为回归算法,同时特别适合集成学习比如随机森林. 1. 决策树ID3算法的信息论基础   1970年昆兰找 ...

  5. ID3和C4.5分类决策树算法 - 数据挖掘算法(7)

    (2017-05-18 银河统计) 决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来判断其可行性的决策分析方法,是直观运用概率分析的一种图解法.由于这种决策分支画 ...

  6. scikit-learn决策树算法类库使用小结

    之前对决策树的算法原理做了总结,包括决策树算法原理(上)和决策树算法原理(下).今天就从实践的角度来介绍决策树算法,主要是讲解使用scikit-learn来跑决策树算法,结果的可视化以及一些参数调参的 ...

  7. 就是要你明白机器学习系列--决策树算法之悲观剪枝算法(PEP)

    前言 在机器学习经典算法中,决策树算法的重要性想必大家都是知道的.不管是ID3算法还是比如C4.5算法等等,都面临一个问题,就是通过直接生成的完全决策树对于训练样本来说是“过度拟合”的,说白了是太精确 ...

  8. ID3决策树算法原理及C++实现(其中代码转自别人的博客)

    分类是数据挖掘中十分重要的组成部分.分类作为一种无监督学习方式被广泛的使用. 之前关于"数据挖掘中十大经典算法"中,基于ID3核心思想的分类算法C4.5榜上有名.所以不难看出ID3 ...

  9. R语言 决策树算法

    定义: 决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解 ...

  10. 决策树算法原理(CART分类树)

    决策树算法原理(ID3,C4.5) CART回归树 决策树的剪枝 在决策树算法原理(ID3,C4.5)中,提到C4.5的不足,比如模型是用较为复杂的熵来度量,使用了相对较为复杂的多叉树,只能处理分类不 ...

随机推荐

  1. Python数据类型(整型,字符串类型,列表)

    一:数据的概念 1.数据是什么 x=10,数据10就是我们要存储的数据. 2.为什么数据要分不同的种类? 因为数据是用来表示状态的,不同的状态就要用不同类型的数据去表示. 3:Python中常见的数据 ...

  2. python 面试题4

    Python面试题 基础篇 分类: Python2014-08-08 13:15 2071人阅读 评论(0) 收藏 举报 最近,整理了一些python常见的面试题目,语言是一种工具,但是多角度的了解工 ...

  3. SDL封装的系统操作(转载)

    Andrew Haung bluedrum@163.com SDL封装很多操作系统的功能,为了保证SDL程序可移植性,最好尽量用这一些封装函数,哪果没有的话,才使用各种操作本地函数.  对于如何封各个 ...

  4. 洛谷 P4093: bzoj 4553: [HEOI2016/TJOI2016]序列

    题目传送门:洛谷P4093. 题意简述: 给定一个长度为 \(n\) 的序列 \(a\). 同时这个序列还可能发生变化,每一种变化 \((x_i,y_i)\) 对应着 \(a_{x_i}\) 可能变成 ...

  5. 【codeforces】【比赛题解】#854 CF Round #433 (Div.2)

    cf一如既往挺丧 看丧题点我! [A]分数 Petya是数学迷,特别是有关于分数的数学.最近他学了所谓一个分数被叫做“真分数”当且仅当其分子小于分母,而一个分数被叫做“最简分数”当且仅当其分子分母互质 ...

  6. GDB调试基础

    GDB调试基础 https://lesca.me/archives/gdb-basic-knowledge.html GDB笔记(二):条件断点.命令列表.监视点 https://lesca.me/a ...

  7. C# 执行固定个数任务自行控制进入线程池的线程数量,多任务同时但是并发数据限定

    思路来源:http://bbs.csdn.NET/topics/390819824,引用该页面某网友提供的方法. 题目:我现在有100个任务,需要多线程去完成,但是要限定同时并发数量不能超过5个. 原 ...

  8. c# CTS 基础数据类型笔记

    C#中的基础数据类型并没有内置于c#语言中,而内置于.net freamework. C#有15个预定义类型,其中13个是值类型,两个是引用类型(string和object) 一.值类型 值类型 数据 ...

  9. C/C++杂记:运行时类型识别(RTTI)与动态类型转换原理

    运行时类型识别(RTTI)的引入有三个作用: 配合typeid操作符的实现: 实现异常处理中catch的匹配过程: 实现动态类型转换dynamic_cast. 1. typeid操作符的实现 1.1. ...

  10. 32 Profiling Go Programs 分析go语言项目

    Profiling Go Programs  分析go语言项目 24 June 2011 At Scala Days 2011, Robert Hundt presented a paper titl ...