机器学习笔记(2)-决策树

这篇博客介绍了决策树的学习过程,包括ID3、C4.5和CART三种算法的原理,如信息熵、信息增益、基尼指数等。博主分享了实现这三个算法的Python代码,并通过实验展示了不同剪枝策略(预剪枝、后剪枝)对决策树性能的影响,以及连续值处理的方法。
摘要由CSDN通过智能技术生成

决策树

一.问题概述

决策树(decision tree)希望从给定的数据集学得一个模型用以对新示例来进行分类,把这个样本分类的任务看作对“当前样本属于正类吗?”这个问题的“决策”或者“判定”的过程。决策树是基于树的结构进行决策的,如下图:
这里写图片描述

二.决策树学习的基本算法
这里写图片描述
三.实现算法
决策树最核心的问题就是如何选择出最优的划分属性,即上述算法中的第8行,一般而言,我们希望决策树的分支节点所包含的样本尽可能的属于同一个类别,即样本的“纯度”越来越高。

  1. ID3决策树算法
    1.1.以信息增益为准则来选择划分属性
    1.2 基本定义
    信息熵(information entropy),是度量样本集合纯度最常用的一种指标,假定样本集合D中第k类样本所占的比例为Pk(k=1,2,…,|y|),则D的信息熵定义为:
    这里写图片描述
    假定离散属性a有V个可能的取值{a1 , a2 , … , aV},若使用a来对样本进行划分,则会产生V个节点,其中第v个分支节点包含了D中所有在属性a上取值为aV的样本,记为Dv。于是可以计算用属性a划分的“信息增益(information gain)”为:
    这里写图片描述
    一般而言,信息增益越大,则意味着用属性a进行划分所得的”纯度提升“越大,因此我们可以使用信息增益为准则来划分属性,即选择属性
    这里写图片描述
    1.3 缺点:信息增益为准则对可取值数目较多的属性有所偏好
  2. C4.5决策树算法
    2.1增益率(gain ratio)的定义:
    这里写图片描述
    其中IV(a)称为属性a的固有值,属性a的可能取值的数目越多,则IV(a)的值通常会越大。
    2.2 由于增益率对可取值数目较多的属性有所偏好,C4.5采用启发式方法:先从候选的划分属性中找出信息增益高于平均水平的属性,再从中选择增益率最高的。
  3. CART决策树算法
    3.1使用“基尼指数(Gini index)”来选择划分属性。一个数据集的纯度可以使用基尼值来度量:
    这里写图片描述
    基尼指数Gini(D)反应了从数据集中随机抽取两个样本不一致的概率。因此,Gini(D)越小,则数据集的纯度越高。
    相应的,属性a的基尼指数定义为:
    这里写图片描述
    4.实现的python代码如下,我这里实现了上述三个算法,根据方法chooseBestFeatureToSplit(dataSet, modelType =’ID3’)的modelType参数来选择相应的算法。
# -*- coding: utf-8 -*-
"""
Decision Tree Source Code for Machine Learning
algorithm:  ID3,C4.5,CART 以信息增益、增益率为准则来选择最优的划分属性
@author leyuan
"""
from math import log
import operator
import treePlotter

def createDataSet():
    """
        产生测试数据
    """
    dataSet = [[1, 1, 'yes'],
               [1, 1, 'yes'],
               [1, 0, 'no'],
               [0, 1, 'no'],
               [0, 1, 'no']]
    labels = ['no surfacing', 'flippers']

    return dataSet, labels


def calcShannonEnt(dataSet):
    """
    计算给定数据集的信息熵(information entropy),
    :param dataSet:
    :return:
    """
    numEntries = len(dataSet)
    labelCounts = {}
    # 统计每个类别出现的次数,保存在字典labelCounts中
    for featVec in dataSet: 
        currentLabel = featVec[-1]
        if currentLabel not in labelCounts.keys():  # 如果当前键值不存在,则扩展字典并将当前键值加入字典
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1
    shannonEnt = 0.0
    for key in labelCounts:
        # 使用所有类标签的发生频率计算类别出现的概率
        prob = float(labelCounts[key])/numEntries
        # 用这个概率计算信息熵
        shannonEnt -= prob * log(prob, 2)  # 取2为底的对数
    return shannonEnt


def calcGini(dataSet):
    """
    计算给定数据集的基尼指数
    :param dataSet:
    :return:
    """
    numExample = len(dataSet)
    lableCounts = {}
    # 统计每个类别出现的次数,保存在字典lableCounts中
    for featVect in dataSet:
        currentLable = featVect[-1]
        # 如果当前键值不存在,则扩展字典将当前键值加入到字典中
        if currentLable not in lableCounts.keys():
            lableCounts[currentLable] = 0
        lableCounts[currentLable] += 1
    gini = 1.0
    for key in lableCounts:
        # 使用所有类标签的频率来计算概率
        prob = float(lableCounts[key])/numExample
        # 计算基尼指数
        gini -= prob**2
    return gini

def splitDataSet(dataSet, axis, value):
    """
    按照给定特征划分数据集
    dataSet:待划分的数据集
    axis:   划分数据集的第axis个特征
    value:  特征的返回值(比较值)
    """
    retDataSet = []
    # 遍历数据集中的每个元素,一旦发现符合要求的值,则将其添加到新创建的列表中
    for featVec in dataSet:
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)

            # extend()和append()方法功能相似,但在处理列表时,处理结果完全不同
            # a=[1,2,3]  b=[4,5,6]
            # a.append(b) = [1,2,3,[4,5,6]]
            # a.extend(b) = [1,2,3,4,5,6]
    return retDataSet


def chooseBestFeatureToSplit(dataSet, modelType ='ID3'):
    """
    选择最好的数据集划分方式,支持ID3,C4.5,CART
    :param dataSet: 数据集
    :param modelType: 决定选择最优划分属性的方式
    :return: 最优分类的特征的index
    """
    # 计算特征数量
    numFeatures = len(dataSet[0]) - 1
    baseEntropy = calcShannonEnt(dataSet)
    bestInfoGain = 0.0
    bestFeature = -1
    infoGainList = []
    gain_ratioList = []
    gini_index_list = []
    for i in range(numFeatures):
        # 创建唯一的分类标签列表
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList)
        # 计算用某种属性划分的信息熵和信息增益
        newEntropy = 0.0
        instrinsicValue = 0.0
        # 基尼指数
        gini_index = 0.0
        for value in uniqueVals:
            # 计算属性的每个取值的信息熵x权重
            subDataSet = splitDataSet(dataSet, i, value)
            prob = len(subDataSet)/float(len(dataSet))
            newEntropy += prob * calcShannonEnt(subDataSet)
            # 计算固有值(instrinsic value)
            instrinsicValue -= prob * log(prob, 2)
            # 计算基尼指数
            gini_index += prob * calcGini(subDataSet)
        # 计算信息增益
        infoGain = baseEntropy - newEntropy
        infoGainList.append(infoGain)
        # 计算增益率
        if instrinsicValue == 0:
            gain_ratio = 0
        else:
            gain_ratio = infoGain/instrinsicValue
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值