您的位置:首页 > 编程语言 > Python开发

统计学习方法《决策树》

2017-04-03 14:02 627 查看

决策树

本博文是《统计学习方法》第5章决策树的学习笔记,后面的Python代码来源于《机器学习实战》(代码中的例子是《统计学习方法》中的)

1 决策树模型

决策树就是一个if-the规则的集合,这个集合具有互斥完备的性质:每一个实例都被一条路径或一条规则所覆盖,而且只被一条路径或一条规则所覆盖。

因此,决策树学习本质上就是从训练数据集中归纳出一组分类规则,主要包括:特征选择决策树的生成决策树的剪枝。下面将围绕这三个方面进行介绍。

1.1 特征选择

在决策树学习时,首先就是选取特征对数据集进行划分。考虑如下决策树学习:

假设给定训练数据集D={(x1,y1),(x2,y2),⋯,(xN,yN)},其中xi=(x(1)i,x(2)i,⋯,x(n)i)为一个样例,n为特征个数,N为样例数,yi∈{1,2,⋯,K},i=1,2,⋯,N为类标签。

数据集有n个特征,那么选取哪个特征进行划分呢?或者说,要利用所有特征对数据集进行划分,特征选择的顺序如何安排才是好的呢?这就是特征选择问题。常用的度量选取特征优劣的方法就是计算信息增益(如ID3算法)、信息增益比(如C4.5算法)。

信息增益

首先介绍熵(entropy)和条件熵(conditional entropy)的概念。

熵是信息论和概率统计中度量信息的一种方法,表示随机变量不确定性的度量。设X是一个取有限个值得离散随机变量,其概率分布为P(X=xi)=pi,i=1,2,⋯,n,则X的熵定义为H(X)=−∑i=1npilog(pi)

熵只依赖于X的分布,与X的取值无关,所以也可以将X的熵记为H(p):H(p)=−∑i=1npilog(pi)

而条件熵H(Y|X)则表示在已知随机变量X的条件下,随机变量Y的不确定性,其定义为:X给定条件下Y的条件概率分布的熵对X的数学期望H(Y|X)=∑i=1npiH(Y|X=xi)

这里的pi=P(X=xi),i=1,2,⋯,n。

当熵和条件熵中的概率由数据估计(如极大似然估计)得到时,所对应的熵和条件熵分别称为经验熵(empirical entropy)和经验条件熵(empirical conditional entropy)。而信息增益表示得知特征X的信息而使得类Y的信息的不确定性减少的程度。

信息增益 information gain:特征A对训练数据集D的信息增益g(D,A)定义为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差,即g(D,A)=H(D)−H(D|A)

一般地,熵H(Y)与条件熵H(Y|X)之差称为互信息(mutual information),决策树学习中的信息增益等价于训练数据集中类与特征的互信息。决策树学习就是利用信息增益准则选择特征的:对训练数据集(或子集)D,计算其每个特征的信息增益,并比它们的大小,选择信息增益最大的特征。

设训练数据集为D,|D|为标本容量.设输出有K个类Ck,k=1,2,⋯,K,|Ck|为属于类Ck的样本个数,∑Kk=1|Ck|=|D|. 特征A有n个不同的取值{a1,a2,⋯,an},根据特征A的取值将D划分为n个子集D1,D2,⋯,Dn,|Di|为Di的样本个数,∑ni=1|Di|=|D|. 记子集Di中属于类Ck的样本的集合为Dik,即Dik=Di∩Ck,|Dik|为Dik的样本个数。

信息增益算法

输入:训练数据集D和特征A;

输出:特征A对训练数据集D的信息增益g(D,A).

(1)计算数据集D的经验熵H(D)

H(D)=−∑k=1K|Ck||D|log2|Ck||D|

(2)计算特征A对数据集D的经验条件熵H(D|A)

H(D|A)=∑i=1n|Di||D|H(Di)=−∑i=1n|Di||D|∑k=1K|Dik||Di|log2|Dik||Di|

(3)计算信息增益

g(D,A)=H(D)−H(D|A)

信息增益比

以信息增益作为划分训练数据集的特征,存在偏向于选择取值较多的特征的问题,可以使用信息增益比(information gain ratio)对这一问题进行校正。

信息增益比:特征A对训练数据集的信息增益比gR(D,A)定义为信息增益g(D,A)与训练数据集D关于特征A的值的熵HA(D)之比,即

gR(D,A)=g(D,A)HA(D)

1.2 决策树生成

主要介绍两种经典的决策树生成算法:ID3和C4.5。

1.2.1 ID3算法

ID3算法核心是:在决策树各个结点上应用信息增益准则选择特征,递归地建立决策树。具体方法:从根结点开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子结点;再对子结点递归调用以上方法。

ID3算法

输入:训练数据集D,特征集A,阈值ϵ;

输出:决策树T

(1)若D中所有实例属于同一类Ck,则T为单结点树,并将类Ck最为该结点的类标记,返回T;

(2)若A=∅,则T为单结点树,并将D中实例数最大的类Ck作为该结点的类标记,返回T;

(3)否则,按信息增益计算方法计算A中特征对D的信息增益,选择信息增益最大的特征Ag;

(4)如果Ag的信息增益小鱼阈值ϵ,则置T为单结点树,并将D中实例数最多的类Ck作为该结点的类标记,返回T;

(5)否则,对Ag的每一可能值ai,依Ag=ai将D分割为若干非空子集Di,将Di中实例数最大的类作为标记,构建子结点,由结点及其子结点构成树T,返回T;

(6)对第i个子结点,以Di为训练集,以A−{Ag}为特征集,递归调用(1)-(5)得到字数Ti,返回Ti。

1.2.2 C4.5算法

C4.5算法与ID3算法相似,只不过在生成的过程中,用信息增益比来选择特征。

1.3 决策树剪枝

如果不对生成的决策树进行剪枝操作,生成的决策树容易过拟合,其原因在于:学习时过多地考虑如何提高对训练数据的正确分类,从而构建出过于复杂的决策树。解决这个问题的办法是考虑决策树的复杂度,对已生成的决策树进行简化。

(剪枝操作的具体过程,后面再补充)

2 决策树算法的Python实现

这里实现的是ID3算法,且未带剪枝操作。参考来源:Machine Learning in Action.

实例来自于《统计学习方法》第5章决策树



# -*- coding: utf-8 -*-
'''
Decision Tree.
Reference:
1.Machine Learning in Action.
2.Statistical Learning Methods,Li,Hang.
'''
from math import log
import operator
def calc_entropy(dataset):
num=len(dataset)#number of samples.
label_count={}
for sample in dataset:
current_label=sample[-1]
if current_label not in label_count.keys():
label_count[current_label]=0
label_count[current_label]+=1
entropy=0.0
for key in label_count:
p=float(label_count[key])/num
entropy-=p*log(p,2)
return entropy
def partition_dataset(dataset,axis,value):
partitioned_dataset=[]
for sample in dataset:
if sample[axis]==value:
reduced_feature=sample[:axis]#this two lines exclude feature sample[axis].
reduced_feature.extend(sample[axis+1:])
partitioned_dataset.append(reduced_feature)
return partitioned_dataset

def choose_best_feature_to_partition(dataset):
num_features=len(dataset[0])-1 #last one element is label.
num_samples=len(dataset)
base_entropy=calc_entropy(dataset)
best_info_gain=0.0
best_feature=-1
for i in range(num_features):
feature_value_list=[sample[i] for sample in dataset]
feature_value_list=set(feature_value_list)
current_entropy=0.0
for value in feature_value_list:
sub_dataset=partition_dataset(dataset,i,value)
p=float(len(sub_dataset))/num_samples
current_entropy+=p*calc_entropy(sub_dataset)
info_gain=base_entropy-current_entropy
if info_gain>best_info_gain:
best_feature=i
best_info_gain=info_gain
return best_feature#,best_info_gain
def majority_vote(label_list):
label_count={}
for label in label_list:
if label not in label_list.key():
label_count[label]=0
label_count[label]+=1
sorted_label_count=sorted(label_count.iteritems(),key=operator.itemgetter(1),reverse=True)
return sorted_label_count[0][0]
def create_tree(dataset,labels):
label_list=[sample[-1] for sample in dataset]
if label_list.count(label_list[0])==len(label_list):
return label_list[0]
if len(dataset[0])==1:
return majority_vote(label_list)
best_feature=choose_best_feature_to_partition(dataset)
best_feature_label=labels[best_feature]
tree={best_feature_label:{}}
del(label_list[best_feature])
feature_value=[sample[best_feature] for sample in dataset]
unique_feature_value=set(feature_value)
for value in unique_feature_value:
sub_labels=labels[:]
tree[best_feature_label][value]=create_tree(partition_dataset(dataset,best_feature,value),sub_labels)
return tree

def create_dataset():
dataset=[['youth','no','no','ordinary','no'],['youth','no','no','good','no'],['youth','yes','no','good','yes'],['youth','yes','yes','ordinary','yes'],['youth','no','no','ordinary','no'],
['middle','no','no','ordinary','no'],['middle','no','no','good','no'],['middle','yes','yes','good','yes'],['middle','no','yes','very good','yes'],['middle','no','yes','very good','yes'],
['old','no','yes','very good','yes'],['old','no','yes','good','yes'],['old','yes','no','good','yes'],['old','yes','no','very good','yes'],['old','no','no','ordinary','no']]
return dataset
dataset=create_dataset()
feature_attributes=['age','having job','own house','credit condition']

best_feature=choose_best_feature_to_partition(dataset)
my_tree=create_tree(dataset,feature_attributes)
print my_tree
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  机器学习 python