决策树1 -- ID3_C4.5算法
声明:
1。本篇为个人对《2012.李航.统计学习方法.pdf》的学习总结,不得用作商用。欢迎转载,但请注明出处(即:本帖地址)。
2,因为本人在学习初始时有非常多数学知识都已忘记,因此为了弄懂当中的内容查阅了非常多资料,所以里面应该会有引用其它帖子的小部分内容。假设原作者看到能够私信我,我会将您的帖子的地址付到以下。
3。假设有内容错误或不准确欢迎大家指正。
4。假设能帮到你,那真是太好了。
简单介绍
决策树是一种主要的分类和回归方法。这里总结的是其分类方法部分。
决策树是一种对实例进行分类的树状结构,eg:
属于类1否?
/ \
/ \
属于且 不属于
无法再分类 且能够继续分类
那属于类2否?
/ \
/ \
属于且 不属于且
无法再分类 无法再分类
特征选择
经过上面的介绍可知:决策树就是用某个特征将样本集合进行分类。那么怎样选择特征就非常重要了。由于每一次分类我们都要选取个能将样本集合分类的最好特征。
以下就介绍选取最优特征的方法。即:ID3算法和C4.5算法。
熵、条件熵、信息增益、信息增益比
就好像我们用皮肤的颜色来区分黄种人、白种人和黑种人一样,ID3和C4.5也须要一个统一的标准来对样本集合进行区分,而这个标准就是:熵、条件熵、信息增益和信息增益比。
我们如果X为一个取有限个值的离散随机变量。且其概率分布为:
P(X=xi) = Pi I =1, 2, …, n
即:pi= 某个类的数量xi / 样本集合总数
于是熵、条件熵、信息增益和信息增益比的定义分别例如以下:
熵:
Ps1:在上式中。若Pi= 0,则定义0log0 = 0.
Ps2:通常上式中的对数以2或e为底。这是熵的单位各自是比特(bit)和纳特(nat)。
由定义可知,熵仅仅依赖于X中类的分布,与X即样本总数无关,所以也可将H(X)记作H(P),即
熵越大,随机变量的不确定性就越大。从定义可验证:0 <= H(P) <= log n
若随机变量仅取两个值0和1。那X的分布为:
P(X=1) = P; P(X=0) = 1 - P; 0 <= P <= 1
那么熵为:
H(P)= -Plog2P + ( -(1-p)log2(1-P) )
条件熵:
条件熵就是在随机变量X已确定的条件下,随机变量Y的条件概率分布的熵对X的数学期望:
上述的X代表样本集合总数。Y代表特征
于是:
Pj即“既属于熵中那个类xi又属于条件熵中这个类的元素的数量 / 属于熵中那个类xi的元素的数量”
信息增益:
g(X,Y) = H(X) – H(X|Y)
信息增益比:
gR(X,Y) = g(X, Y) / H(X)
PS:“经验熵”和“经验条件熵”就是由数据预计(特别是极大似然预计)得到的“熵”和“条件熵”的概率。
在掌握了这些后就能够開始算法了。
决策树学习经常使用的算法有ID3,C4.5和CART。
PS:由于ID3和C4.5仅仅有树的生成,所以它们生成的树easy产生过拟合。
首先是ID3。
ID3算法
描写叙述:
输入:
训练数据集D。特征集A,阈值ε。
输出:
决策树T。
过程:
1,若当前可用的D中的全部实例仅有一个类C,则将类C作为当前T的当前结点,返回T;
2,若A=Ф(即:没有可用特征。如:一開始就没有特征给你用或经过一定次数的分类后,特征已用过一遍),则将D中实例数最大的那个类作为T的当前结点。返回T。
3,若A≠Ф,则计算各特征的信息增益。选择信息增益最大的特征Ag;
4,若Ag的信息增益小于阈值ε,则用当前D中实例数最大的类作为该节点的类标记。返回T。
5,否则,依据Ag中每个值ai将当前的D切割成若干个非空子集Di。将Di中实例数最大的类作为标记,构建子结点。由节点集子结点构成T,返回T;
6。对第i个子结点,以Di为训练集,以ai为特征集,递归的调用1~5步。得到子树Ti。返回Ti。
样例:
对例如以下数据建立决策树:
(贷款申请样本数据表)
ID |
年龄 |
有工作 |
有自己的房子 |
信贷情况 |
类别(是否能贷到款) |
1 |
青年 |
否 |
否 |
一般 |
否 |
2 |
青年 |
否 |
否 |
好 |
否 |
3 |
青年 |
是 |
否 |
好 |
是 |
4 |
青年 |
是 |
是 |
一般 |
是 |
5 |
青年 |
否 |
否 |
一般 |
否 |
6 |
中年 |
否 |
否 |
一般 |
否 |
7 |
中年 |
否 |
否 |
好 |
否 |
8 |
中年 |
是 |
是 |
好 |
是 |
9 |
中年 |
否 |
是 |
很好 |
是 |
10 |
中年 |
否 |
是 |
很好 |
是 |
11 |
老年 |
否 |
是 |
很好 |
是 |
12 |
老年 |
否 |
是 |
好 |
是 |
13 |
老年 |
是 |
否 |
好 |
是 |
14 |
老年 |
是 |
否 |
很好 |
是 |
15 |
老年 |
否 |
否 |
一般 |
否 |
解:
1,计算熵:
由于该表的数据被分为两类:给予贷款,不给予贷款。
所以:
2。计算全部的条件熵:
我们用A1代表年龄。D1, D2,D3 代表中、青、老年。
由于中青老年各五人。所以:
而对于每一个年龄段都有:“能够贷款的青中老年”和“不可贷款的青中老年”。
所以。对于青年:
于是中年和老年同理,最后得:
H(T|A1)
同理。对于是否有工作(A2),是否有房子(A3),信贷情况(A4):
H(T|A2)= 0.647
H(T|A3)= 0.551
H(T|A4)= 0.608
3,计算信息增益
g(T,A1)= H(T) – H(T|A1) = 0.971 – 0.888 = 0.083
g(T,A2)= H(T) – H(T|A2) = 0.324
g(T,A3)= H(T) – H(T|A3) = 0.420
g(T,A4)= H(T) – H(T|A4) = 0.363
4,由于g(T,A3) 最大,所以选择“是否有房子”作为根节点的特征。于是这将数据集分成了两部分:T1(有房)和T2(无房)
因为T1的全可贷款(全部的元素都属于一类),所以它成为一个叶子节点。
而T2中既有能贷到款的也有贷不到的(全部的元素不属于一类),所以对于T2须要从特征A1(年龄)。A2(有无工作),A4(信贷情况)中选出一个新特征。
到此形成例如以下决策树:
A3:有房子吗
/ \
T1:有房子 T2:无房子
全能贷到款 有的能贷到,有的不能
5,对T2这个数据集再次调用1~3步,计算信息增益(注意:需用当前的数据集T2又一次计算),得:
g(T2,A1) = H(T2) – H(T2|A1) = 0.251
g(T2,A2) = H(T2) – H(T2|A2) = 0.918
g(T2,A4) = H(T2) – H(T2|A4) = 0.474
于是选择A2(有无工作)来作为当前特征。
到此形成例如以下决策树:
A3:有房子吗
/ \
T1:有房子 T2:无房子。有工作吗?
全能贷到款 / \
有工作 无工作
全能贷到款 全都贷不到
由于到此。全部的子结点的元素全都仅仅属于一个类,所以到此以全然划分。
终于决策树如上。
C4.5算法
C4.5算法就是将ID3第三步的信息增益换成信息增益比。其它不变。
#-*-coding:utf-8-*-
# LANG=en_US.UTF-8
# ID3 和 ID4 算法
# 文件名称:ID3_ID4.py
# import sys
import math
import copy dict_all = {
# 1: 青年;2:中年;3:老年
'_age' : [
1, 1, 1, 1, 1,
2, 2, 2, 2, 2,
3, 3, 3, 3, 3,
], # 0:无工作;1:有工作
'_work' : [
0, 0, 1, 1, 0,
0, 0, 1, 0, 0,
0, 0, 1, 1, 0,
], # 0:无房子;1:有房子
'_house' : [
0, 0, 0, 1, 0,
0, 0, 1, 1, 1,
1, 1, 0, 0, 0,
], # 1:信贷情况一般;2:好;3:很好
'_credit' : [
1, 2, 2, 1, 1,
1, 2, 2, 3, 3,
3, 2, 2, 3, 1,
],
} # 0:未申请到贷款;1:申请到贷款
_type = [
0, 0, 1, 1, 0,
0, 0, 1, 1, 1,
1, 1, 1, 1, 0,
] # 二叉树结点
class BinaryTreeNode( object ):
def __init__( self, name=None, data=None, left=None, right=None, father=None ):
self.name = name
self.data = data
self.left = left
self.right = left # 二叉树遍历
class BTree(object):
def __init__(self,root=0):
self.root = root # 中序遍历
def inOrder(self,treenode):
if treenode is None:
return self.inOrder(treenode.left)
print treenode.name, treenode.data
self.inOrder(treenode.right) # 遍历类型,统计每一个类型的数量,将其保存到字典中
# 如:对于 _type: 有9个类型1。6个类型0。 # 于是返回:{'1': 9.0, '0': 6.0}
# 參数:类型列表
def get_type_num( type_list ):
type_dict = {}
tmp_item = '' for item in type_list:
item = str(item)
if tmp_item != item:
if item in type_dict.keys():
type_dict[item] += 1.0
else:
type_dict[item] = 1.0
tmp_item = item
else:
type_dict[item] += 1.0 return type_dict # 获得熵
# 參数:类型列表
def get_entropy( type_list ):
entropy = 0.0
len_type = len(type_list)
type_dict = get_type_num( type_list )
# 计算熵
for key in type_dict.keys():
tmp_num = type_dict[key] / len_type
entropy = entropy - tmp_num * math.log(tmp_num, 2) return float('%.3f' % entropy) # 获得条件熵
# 參数:特征列表,类型列表,序号列表
# 如:
# 第一轮时以 _house 为特征进行筛选(筛选使用ID3或ID4。不是在此函数中),这是參数分别为:_house, _type, [0, 1, ..., 15]
# 第一轮结束后:左子树的特征序号列表为:[3, 7, 8, 9, 10, 11],右子树的特征序号列表为:[0, 1, 2, 4, 5, 6, 12, 13, 14]
# 于是第二轮在对右子树以 _work 为特征进行筛选时传入參数:_house, _type, [0, 1, 2, 4, 5, 6, 12, 13, 14]
def get_conditional_entropy( value_list, type_list, num_list ):
# 整理 value_list 以 num_list 为序号形成的新列表中的不同类别
# value_dict = {特征名 : 包括的类别列表}
# eg:对于 _work
# 其“原始内容”和“以 num_list(即:[0, 1, 2, 4, 5, 6, 12, 13, 14]) 为序号形成的新列表为”分别例如以下:
# [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0]
# [0, 0, 1, 0, 0, 0, 1, 1, 0]
# 新列表有3个类型1和6个类型2。于是该函数返回:{'1': [1, 1, 1], '0': [0, 0, 0, 0, 0, 0]}
def get_value_type():
value_dict = {}
tmp_type = ''
tmp_item = '' for num in num_list:
item = str( value_list[num] )
if tmp_item != item:
if item in value_dict.keys():
value_dict[item].append(type_list[num])
else:
value_dict[item] = [type_list[num],]
tmp_item = item
else:
value_dict[item].append(type_list[num]) return value_dict value_dict = get_value_type()
conditional_entropy = 0
for key in value_dict.keys():
tmp_num = float( '%.3f' % (float(len(value_dict[key]))/len(value_list)) )
conditional_entropy += float( '%.3f' % (tmp_num * get_entropy(value_dict[key])) ) return conditional_entropy # 获得信息增益
def get_information_gain( value_list, type_list, num_list ):
return float( '%.3f' % (get_entropy( type_list ) - get_conditional_entropy( value_list, type_list, num_list )) ) # 获得信息增益比
def get_information_gain_ratio( value_list, type_list, num_list ):
entropy = get_entropy( type_list )
information_gain = entropy - get_conditional_entropy( value_list, type_list, num_list )
return float( '%0.3f' % (information_gain/entropy) ) # ID3 算法
def ID3( data, type_list, threshold ):
# 获得最大的信息增益
def get_max_information_gain( num_list ):
step = 'continue'
tmp_value = 0.0
feature_name = '' for key in data.keys():
information_gain = get_information_gain( data[key], type_list, num_list )
if information_gain > tmp_value:
feature_name = key
tmp_value = information_gain # 假设信息增益小于阈值,则告诉后面的程序。不用在迭代了,到此就可以
if information_gain < threshold:
step = 'over' return feature_name, step # 进行分类
def classify( root, note_name, note_data, note_type ):
# 将'特征可能值名字'追加到 root.name 中
# 将[样本序号的列表]合并到 root.data 中
root.name.append( note_name )
root.data.extend( note_data ) # note_type=='exit' 意味着当前的数据所有属于某一类。不用在分类了
if not data or note_type=='exit':
return feature_name, step = get_max_information_gain( note_data ) # 依据特征的可能值将样本数据分成数个集合。并保存成“特征字典”。
# 字典结构为:{ '特征可能值名字': [样本序号的列表] }
feature_dict = {}
tmp_item = ''
for num in note_data:
item = str( data[feature_name][num] )
if tmp_item != item:
if item in feature_dict.keys():
feature_dict[item].append(num)
else:
feature_dict[item] = [num, ]
tmp_item = item
else:
feature_dict[item].append(num) # 从样本集合中将该特征删除
del data[feature_name] # 准备左子节点和右子节点。节点的 name 和 data 是个空列表
root.left = BinaryTreeNode( [], [] )
root.right = BinaryTreeNode( [], [] ) # 计算“特征字典”中各个集合中是属于“能贷贷款”的多还是“不能贷贷款”的多
# 假设是前者:
# 递归调用 classify,形成左子节点
# 假设是后者:
# 递归调用 classify。形成右子节点
for key in feature_dict.keys():
num_yes = 0; num_no = 0
for num in feature_dict[key]:
if type_list[num] == 1:
num_yes = num_yes + 1
elif type_list[num] == 0:
num_no = num_no + 1
else:
print 'ERROR: wrong type in _type'
exit() note_type = 'not_exit'
if num_yes == 0 or num_no == 0 or step == 'over':
note_type = 'exit' if num_yes >= num_no:
classify( root.left, '%s:%s' % (feature_name, key), feature_dict[key], note_type )
else:
classify( root.right, '%s:%s' % (feature_name, key), feature_dict[key], note_type ) return root tmp_list = []
for num in xrange( len(dict_all[dict_all.keys()[0]]) ):
tmp_list.append( num )
return classify( BinaryTreeNode( [], [] ), 'root', tmp_list, 'not_exit' ) # C4.5 算法
def C4_5( data, type_list, threshold ):
# 获得最大的信息增益比
def get_max_information_gain( num_list ):
step = 'continue'
tmp_value = 0.0
feature_name = '' for key in data.keys():
information_gain_ratio = get_information_gain_ratio( data[key], type_list, num_list )
if information_gain_ratio > tmp_value:
feature_name = key
tmp_value = information_gain_ratio # 假设信息增益比小于阈值。则告诉后面的程序,不用在迭代了,到此就可以
if information_gain_ratio < threshold:
step = 'over' return feature_name, step # 进行分类
def classify( root, note_name, note_data, note_type ):
# 将'特征可能值名字'追加到 root.name 中
# 将[样本序号的列表]合并到 root.data 中
root.name.append( note_name )
root.data.extend( note_data ) # note_type=='exit' 意味着当前的数据所有属于某一类。不用在分类了
if not data or note_type=='exit':
return feature_name, step = get_max_information_gain( note_data ) # 依据特征的可能值将样本数据分成数个集合,并保存成“特征字典”。
# 字典结构为:{ '特征可能值名字': [样本序号的列表] }
feature_dict = {}
tmp_item = ''
for num in note_data:
item = str( data[feature_name][num] )
if tmp_item != item:
if item in feature_dict.keys():
feature_dict[item].append(num)
else:
feature_dict[item] = [num, ]
tmp_item = item
else:
feature_dict[item].append(num) # 从样本集合中将该特征删除
del data[feature_name] # 准备左子节点和右子节点。节点的 name 和 data 是个空列表
root.left = BinaryTreeNode( [], [] )
root.right = BinaryTreeNode( [], [] ) # 计算“特征字典”中各个集合中是属于“能贷贷款”的多还是“不能贷贷款”的多
# 假设是前者:
# 递归调用 classify,形成左子节点
# 假设是后者:
# 递归调用 classify,形成右子节点
for key in feature_dict.keys():
num_yes = 0; num_no = 0
for num in feature_dict[key]:
if type_list[num] == 1:
num_yes = num_yes + 1
elif type_list[num] == 0:
num_no = num_no + 1
else:
print 'ERROR: wrong type in _type'
exit() note_type = 'not_exit'
if num_yes == 0 or num_no == 0 or step == 'over':
note_type = 'exit' if num_yes >= num_no:
classify( root.left, '%s:%s' % (feature_name, key), feature_dict[key], note_type )
else:
classify( root.right, '%s:%s' % (feature_name, key), feature_dict[key], note_type ) return root tmp_list = []
for num in xrange( len(dict_all[dict_all.keys()[0]]) ):
tmp_list.append( num )
return classify( BinaryTreeNode( [], [] ), 'root', tmp_list, 'not_exit' ) # 阈值
threshold = 0.3
dict_all_id3 = copy.deepcopy( dict_all )
root = ID3( dict_all_id3, _type, threshold )
bt = BTree( root )
print '--------------ID3----------------'
bt.inOrder( bt.root )
print '---------------------------------\n' dict_all_c45 = copy.deepcopy( dict_all )
root = C4_5( dict_all_c45, _type, threshold )
bt = BTree( root )
print '--------------C4.5----------------'
bt.inOrder( bt.root )
print '----------------------------------\n'
决策树1 -- ID3_C4.5算法的更多相关文章
- 决策树之C4.5算法
决策树之C4.5算法 一.C4.5算法概述 C4.5算法是最常用的决策树算法,因为它继承了ID3算法的所有优点并对ID3算法进行了改进和补充. 改进有如下几个要点: 用信息增益率来选择属性,克服了ID ...
- python数据分析算法(决策树2)CART算法
CART(Classification And Regression Tree),分类回归树,,决策树可以分为ID3算法,C4.5算法,和CART算法.ID3算法,C4.5算法可以生成二叉树或者多叉树 ...
- 深入了解机器学习决策树模型——C4.5算法
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第22篇文章,我们继续决策树的话题. 上一篇文章当中介绍了一种最简单构造决策树的方法--ID3算法,也就是每次选择一个特 ...
- 决策树的基本ID3算法
一 ID3算法的大致思想 基本的ID3算法是通过自顶向下构造决策树来进行学习的.我们首先思考的是树的构造从哪里开始,这就涉及到选择属性进行树的构造了,那么怎样选择属性呢?为了解决这个问题,我们使用统 ...
- R语言︱决策树族——随机森林算法
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 笔者寄语:有一篇<有监督学习选择深度学习 ...
- 机器学习之决策树(ID3)算法
最近刚把<机器学习实战>中的决策树过了一遍,接下来通过书中的实例,来温习决策树构造算法中的ID3算法. 海洋生物数据: 不浮出水面是否可以生存 是否有脚蹼 属于鱼类 1 是 是 是 2 ...
- 机器学习第5周--炼数成金-----决策树,组合提升算法,bagging和adaboost,随机森林。
决策树decision tree 什么是决策树输入:学习集输出:分类觃则(决策树) 决策树算法概述 70年代后期至80年代初期,Quinlan开发了ID3算法(迭代的二分器)Quinlan改迚了ID3 ...
- 决策树之C4.5算法学习
决策树<Decision Tree>是一种预測模型,它由决策节点,分支和叶节点三个部分组成. 决策节点代表一个样本測试,通常代表待分类样本的某个属性,在该属性上的不同測试结果代表一个分支: ...
- 决策树CART回归树——算法实现
决策树模型 选择最好的特征和特征的值进行数据集划分 根据上面获得的结果创建决策树 根据测试数据进行剪枝(默认没有数据的树分支被剪掉) 对输入进行预测 模型树 import numpy as np de ...
随机推荐
- NPM 上传自己的包
NPM 上传自己的包 项目中经常 npm install,npm init啥的,那么如何上传自己的包到npm上呢. 注册账号 NPM官网 本地弄一个包 创建npm_test 文件夹 注:不能够有一些特 ...
- 030.Zabbix分布式部署
一 分布式Zabbix介绍 zabbix proxy 可以代替 zabbix server 收集性能和可用性数据,然后把数据汇报给 zabbix server,并且在一定程度上分担了zabbix se ...
- Dart语言特性必备了解!
学习Dart语言,必须将以下的概念熟记于心: 在dart语言中,一切皆为对象.所有的对象都是一个类的实例.甚至整数.函数.null也看做是对象.所有的对象都继承于Object类 尽管Dart是强类型语 ...
- 小程序使用 rpx 单位 转 px的方法(用于动画、canvas画图)
1.需要借助的API:wx.getSystemInfoSync(); 通过API可获取的值: // 在 iPhone6 下运行: var systemInfo = wx.getSystemInfoSy ...
- Java中A instanceof B是什么意思?
instanceof用来判断内存中实际对象A是不是B类型 出现这种情况经常是需要强制转换的时候class Dog extends Animal譬如dog定义了自己的方法wangwang Animal ...
- sicp 习题
1.11 求f(n)=f(n-1)+2*f(n-2)+3*f(n-3) #lang racket (define (fff n) (define (fff-iter a b c n) (if (= n ...
- 在web.xml中配置struts2拦截器
<!-- 配置Struts2的核心的过滤器 --> <filter> <filter-name>struts2</filter-name> <fi ...
- window 10系统怎样手动更改电脑的时间
win10系统的电脑显示时间默认的是自动网络校时,也就是电脑的时间跟网络时间同步,那么win10系统怎样手动更改电脑时间呢? 点击电脑左下方的win图标,找到菜单里的[设置] 点击菜单里的[设置],弹 ...
- copy unicode HTML to clipboard
How to copy unicode HTML code to the clipboard in html format, so it can be pasted into Writer, Word ...
- http://blog.csdn.net/wzzvictory/article/details/16994913
原文地址:http://blog.csdn.net/wzzvictory/article/details/16994913 一.什么是instancetype instancetype是cla ...