统计学习方法《决策树》

决策树

本博文是《统计学习方法》第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=DiCk |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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值