决策树
一.决策树的基本思想
决策树是一种基本的分类与回归方法,它可以看作if-then规则的集合,也可以认为是定义在特征空间与类空间上的条件概率分布。
将决策树转换成if-then规则的过程如下:
- 由决策树的根节点到叶节点的每一条路径构建一条规则;
- 路径内部结点的特征对应规则的条件;
- 叶节点的类对应规则的结论.
决策树的路径具有一个重要的性质:互斥且完备,即每一个样本均被且只能被一条路径所覆盖。
决策树学习算法主要由三部分构成:
- 特征选择
- 决策树生成
- 决策树的剪枝
下面,从这三方面进行理论介绍,并提供相应的Python代码实现。
二. 决策树的特征选择
如果利用一个特征进行分类的结果与随机分类的结果无异,则可以认为这个特征是不具备分类能力的。把这样的特征去掉,对决策树的分类精度应该影响不大。
而我们应该基于什么准则来判定一个特征的分类能力呢?
这时候,需要引入一个概念:信息增益.
信息增益
在介绍信息增益之前,先了解一个概念:熵(entropy).
熵(entropy)
在信息论与概率论中,熵(entropy)用于表示随机变量不确定性的度量。
熵越大,则随机变量的不确定性越大。
条件熵(conditional entropy)
信息增益表示的是:得知特征X的信息而使得类Y的信息的不确定性减少的程度。
信息增益比(information gain ratio)
以信息增益作为特征选择准则,会存在偏向于选择取值较多的特征的问题。可以采用信息增益比对这一问题进行校正。
特征A对训练数据集D的信息增益比定义为其信息增益与训练集D关于特征A的值的熵之比
# 对y的各种可能的取值出现的个数进行计数.。其他函数利用该函数来计算数据集和的混杂程度
def uniquecounts(rows):
results = {}
for row in rows:
#计数结果在最后一列
r = row[len(row)-1]
if r not in results:results[r] = 0
results[r]+=1
return results # 返回一个字典
# 熵
def entropy(rows):
from math import log
log2 = lambda x:log(x)/log(2)
results = uniquecounts(rows)
#开始计算熵的值
ent = 0.0
for r in results.keys():
p = float(results[r])/len(rows)
ent = ent - p*log2(p)
return ent
三.决策树的生成
决策树的生成算法有很多变形,这里介绍几种经典的实现算法:ID3算法,C4.5算法和CART算法。这些算法的主要区别在于分类结点上特征选择的选取标准不同。下面详细了解一下算法的具体实现过程。
ID3算法
ID3算法的核心是在决策树的各个结点上应用信息增益准则进行特征选择。具体做法是:
- 从根节点开始,对结点计算所有可能特征的信息增益,选择信息增益最大的特征作为结点的特征,并由该特征的不同取值构建子节点;
- 对子节点递归地调用以上方法,构建决策树;
- 直到所有特征的信息增益均很小或者没有特征可选时为止。
C4.5算法
C4.5算法与ID3算法的区别主要在于它在生产决策树的过程中,使用信息增益比来进行特征选择。
基尼指数
如果对训练集建立完整的决策树,会使得模型过于针对训练数据,拟合了大部分的噪声,即出现过度拟合的现象。为了避免这个问题,有两种解决的办法:
- 当熵减少的数量小于某一个阈值时,就停止分支的创建。这是一种贪心算法。
- 先创建完整的决策树,然后再尝试消除多余的节点,也就是采用减枝的方法。
具体的算法如下:
\1. 计算每个节点的经验熵;
\2. 递归地从树的叶节点向上回缩,如果将某一个父节点的所有叶节点合并,能够使得其损失函数减小,则进行剪枝,将父节点变成新的叶节点;
\3. 返回2,直到不能继续合并。
# 决策树的剪枝
def prune(tree,mingain):
# 如果分支不是叶节点,则对其进行剪枝
if tree.tb.results == None:
prune(tree.tb,mingain)
if tree.fb.results == None:
prune(tree.fb,mingain)
# 如果两个子分支都是叶节点,判断是否能够合并
if tree.tb.results !=None and tree.fb.results !=None:
#构造合并后的数据集
tb,fb = [],[]
for v,c in tree.tb.results.items():
tb+=[[v]]*c
for v,c in tree.fb.results.items():
fb+=[[v]]*c
#检查熵的减少量
delta = entropy(tb+fb)-(entropy(tb)+entropy(fb)/2)
if delta < mingain:
# 合并分支
tree.tb,tree.fb = None,None
tree.results = uniquecounts(tb+fb)
# test
tree = buildtree(my_data,scoref = giniimpurity)
prune(tree,0.1)
printtree(tree)
{‘None’: 7, ‘Premium’: 3, ‘Basic’: 6}
优点
- - 易于理解和解释,甚至比线性回归更直观;
- - 与人类做决策思考的思维习惯契合;
- - 模型可以通过树的形式进行可视化展示;
= None,None
tree.results = uniquecounts(tb+fb)
test
tree = buildtree(my_data,scoref = giniimpurity)
prune(tree,0.1)
printtree(tree)
{‘None’: 7, ‘Premium’: 3, ‘Basic’: 6}
优点
- - 易于理解和解释,甚至比线性回归更直观;
- - 与人类做决策思考的思维习惯契合;
- - 模型可以通过树的形式进行可视化展示;
- - 可以直接处理非数值型数据,不需要进行哑变量的转化,甚至可以直接处理含缺失值的数据;