决策树与ID3算法

1.概念与目的

决策树是一种基本的分类与回归方法.它可以认为是if-then规则的集合,也可以认为是定义在特征空间与类空间上的条件概率分布.主要优点是模型具有可读性,分类速度快.
决策树主要抓住三个步骤:特征选择、决策树的生成和决策树的修剪
CART决策树也叫分类与回归决策树,注意掌握生成时最优切分变量和切分点的算法生成的思想。
在这里插入图片描述

2.决策树模型

分类决策树模型是一种描述对实例进行分类的树形结构。决策树由节点(node)和有向边(directed edge)组成。节点有两种类型:内部节点(internal node)和叶节点。内部节点表示一个特征或属性,叶节点表示一个类。
用决策树分类,从根节点开始,对实例的某个特征进行测试,根据测试的结果,将实例分别到其子节点;这时每个子节点对于着该特征的一个取值,如此递归直到叶节点,最后将实例分到叶节点的类中去。决策树的路劲具有互斥且完备的性质

3.策略

决策树学习本质上是从训练数据集中归纳出一组分类规则.我们需要的是一个与训练数据矛盾较小,同时具有很好的泛化能力的决策树.决策树学习的损失函数通常是正则化的极大似然函数,决策树学习的策略是以损失函数为目标函数的最小化。当损失函数确定后,学习问题就变为在损失函数意义下选择最优决策树的问题。但是从所有的决策时中选取最优决策树是NP完全问题,所以现实中通常采用启发式方法,近似求解这一最优化问题,得到次最优的解。

决策树学习
假定给定训练数据集T=(x(1),y(1)),(x(2),y(2)),…,(x(m),y(m)),其中x(i)=(x1,x2,…,xn)T为输入实例(特征向量),n为特征个数,y(i)∈1,2,…,k为类标记,i=1,2,…,m,m为样本容量。学习的目标是根据给定的训练数据集构建一个决策树模型,使它能够对实例进行正确的分类。

开始时,将所有训练数据都放在根节点,然后选择一个最优特征,然后将数据集分割成子集,如果某个子集里面的数据能够被基本正确分类,则构建叶节点;如果某个子集不能被正确分类,则继续选择一个新的最优特征,继续分割数据,一直递归下去,直到所有的数据集被正确分类,或没有合适的特征为止。

以上方法对未知的数据未必有好的分类能力,可能发生过拟合现象,需要对生成的决策树进行剪枝,使得它有更好的泛化能力。
总结下来,学习算法包括 特征选择->决策树生成->决策时剪枝的过程。生成只考虑局部最优,剪枝则考虑全局最优。

4.特征选择

原则:
如果利用一个特征进行分类的结果与随机分类的结果没有很大差别,则称这个特征是没有分类能力的.扔掉这样的特征对决策树学习的精度影响不大.通常特征选择的准则是信息增益或信息增益比。

(1)信息熵:
熵是衡量随机变量不确定性的度量.熵越大,随机变量的不确定性就越大.信息熵是信息量的期望
在这里插入图片描述
条件熵表示在已知随机变量X的条件下随机变量Y的不确定性.
在这里插入图片描述
(2)信息增益
信息增益(information gain)表示得知特征X的信息而使得类Y的信息不确定性减少。
特征A对训练数据集D的信息增益g(D,A),定义为集合D的经验熵H(D)与特征A在给定条件下D的经验条件熵H(D|A)之差,即
g(D,A)=H(D)−H(D|A)
一般地,熵H(X)与条件熵H(Y|X)之差称为互信息(mutual information)。
在给定训练数据集D和特征A,经验熵H(D)表示对数据集D进行分类的不确定性。而经验条件熵H(D|A)表示在特征A给定的条件下对数据集D进行分类的不确定性,那么它们的差就表示由于特征A而使得对数据集D的分类的不确定性减少的程度。信息增益大的特征具有更强的分类能力。
(3)信息增益算法
假设训练数据集为D,|D|表示样本容量,即样本个数。设有K个类Ck,k=1,2,…,K,|Ck|为属于类Ck的样本个数,∑k=1K|Ck|=|D|。
设特征A有n个不同的取值a1,a2,…,an,根据特征A的取值将D划分为n个子集D1,D2,…,Dn,|Di|为Di的样本个数,∑i=1n|Dk|=|D|。记子集Di中属于类Ck的样本集合为Dik,|Dik|为Dik的样本个数。

算法:
输入:训练数据集D和特征A
输出:特征A对训练数据集D的信息增益g(D,A)
1)计算数据集D的经验熵H(D)
在这里插入图片描述
2)计算特征A对数据集D的经验条件熵H(D|A)
在这里插入图片描述
3)计算信息增益
g(D,A)=H(D)−H(D|A)

(4)信息增益比
以信息增益比作为划分训练数据集的特征,存在偏向于选择取值较多的特征的问题。使用信息增益比(information gain ratio)可以对这个问题进行校正。
特征A对训练数据集D的信息增益比gR(D,A)定义为信息增益g(D,A)与训练数据集D关于特征A的值的熵HA(D)之比,即
在这里插入图片描述

5.决策树的生成

(1)ID3算法:
核心是在决策树各个结点上应用信息增益准则选择信息增益最大且大于阈值的特征,递归地构建决策树.ID3相当于用极大似然法进行概率模型的选择.由于算法只有树的生成,所以容易产生过拟合.
(2)C4.5算法:
C4.5算法与ID3算法相似,改用信息增益比来选择特征.

6.决策树的剪枝

(1)在学习时过多考虑如何提高对训练数据的正确分类,从而构建出过于复杂的决策树**,产生过拟合现象.解决方法是对已生成的决策树进行简化,称为剪枝.**
(2)设树的叶结点个数为|T|,每个叶结点有Nt个样本点,其中k类样本点有Ntk个,剪枝往往通过极小化决策树整体的损失函数
在这里插入图片描述
来实现,其中经验熵.剪枝通过加入a|T|项来考虑模型复杂度,实际上就是用正则化的极大似然估计进行模型选择.
(3)剪枝算法:
剪去某一子结点,如果生成的新的整体树的损失函数值小于原树,则进行剪枝,直到不能继续为止.具体可以由动态规划实现.

6.ID3算法代码实现

ID3算法对比:C4.5决策树算法,参考《数据挖掘十大算法之C4.5算法》;
区别:ID3算法是计算信息增益值,而C4.5算法采用的是信息增益比,对分裂属性的目标函数做出了改进。

# -*- coding: utf-8 -*-
from math import log
from collections import Counter

class DecisionTree(object):
    def __init__(self, input_data, labels):
        pass

    def create_decision_tree(self, data_set, labels): # 输出树形结构
        class_list = [data[-1] for data in data_set]
        if class_list.count(class_list[0]) == len(class_list): # 如果剩下的数据集的类别都一样
            return class_list[0]
        if len(data_set[0]) == 1:                              # 如果数据集没有特征,只剩下类别,选择类别最多的输出
            major_label = Counter(data_set).most_common(1)[0]
            return major_label

        feature_index = self.get_feature_with_biggest_gain(data_set, labels) # 获取最大信息增益的特征
        feature_name = labels[feature_index]
        del labels[feature_index]

        feature_set = set([ data[feature_index] for data in data_set ]) # 找到该特征的所有可能取值
        decision_tree = {feature_name: {}}
        for i in feature_set: 
        # 遍历该特征的所有取值,将数据集分割成各个子集,然后递归对各个子集进行同样的特征选择
            feature_data_list = [ data for data in data_set if data[feature_index] == i ] # 满足
            new_data_list = []
            for j in feature_data_list: # 移除已经选择的特征,获取子集
                new_data = j[:]
                del new_data[feature_index]
                new_data_list.append(new_data)
            #print(i, new_data_list)
            new_lables = labels[:]
            decision_tree[feature_name][i] = self.create_decision_tree(new_data_list, new_lables)

        return decision_tree

    def cal_data_set_entropy(self, data_set): # 计算数据集的经验熵
        total_num = len(data_set)
        class_list = [data[-1] for data in data_set]
        class_dict = dict()
        for i in class_list:
            ck_num = class_dict.get(i, 0)
            class_dict[i] = ck_num + 1

        entropy = 0
        for k in class_dict:
            ck_rate = float(class_dict[k])/total_num
            entropy -= ck_rate * log(ck_rate, 2)
        return entropy

    def get_feature_with_biggest_gain(self, data_set, labels): #获取最大信息增益的特征
        feature_num = len(labels)
        data_entropy = self.cal_data_set_entropy(data_set)
        biggest_gain_index = None
        biggest_gain = 0
        for i in range(feature_num):
        # 遍历所有特征,找出最大的信息增益特征
            condition_entroy = self.cal_feature_condition_entropy(data_set, i)
            gain = data_entropy - condition_entroy
            if gain > biggest_gain:
                biggest_gain_index = i
                biggest_gain = gain
        #print(labels[biggest_gain_index], biggest_gain)
        return biggest_gain_index

    def cal_feature_condition_entropy(self, data_set, index): # 计算某个特征的条件熵
        total_num = len(data_set)
        feature_list = [data[index] for data in data_set]
        feature_dict = dict()
        for i in feature_list:
            feature_num = feature_dict.get(i, 0)
            feature_dict[i] = feature_num + 1

        condition_entropy = 0
        for k in feature_dict:
            feature_rate = float(feature_dict[k])/total_num
            feature_data_set = [data for data in data_set if data[index] == k]
            entropy = self.cal_data_set_entropy(feature_data_set)
            condition_entropy += feature_rate * entropy
        return condition_entropy

train_data = "*/input/3.DecisionTree/lenses.txt"
with open(train_data) as f:
    lenses = [line.strip().split('\t') for line in f.readlines()] # 特征之间用tab键隔离开
    labels = ['age', 'prescript', 'astigmatic', 'tearRate']

#[['young', 'myope', 'no', 'reduced', 'no lenses'], 
# ['young', 'myope', 'no', 'normal',  'soft']
dTree = DecisionTree(lenses, labels)
print(dTree.create_decision_tree(lenses, labels))
发布了11 篇原创文章 · 获赞 0 · 访问量 653

猜你喜欢

转载自blog.csdn.net/qq_28406091/article/details/102963210