数据挖掘之决策树

1、引言                                                                    



    决策树是建立在信息论基础之上,对数据进行分类挖掘的一种方法。其思想是,通过一批已知的训练数据建立一棵决策树,然后利用建好的决策树,对数据进行预测。决策树的建立过程可以看成是数据规则的生成过程。由于基于决策树的分类方法结构简单,本身就是人们能够理解的规则。其次,决策树方法计算复杂度不大,分类效率高,能够处理大数据量的训练集;最后,决策树方法的分类精度较高,对噪声数据有较好的健壮性,符合一般系统的要求。说了这么多,可能还不是太了解决策树,用一个例子来说明吧。

套用俗语,决策树分类的思想类似于找对象。现想象一个女孩的母亲要给这个女孩介绍男朋友,于是有了下面的对话:

女儿:多大年纪了?
      母亲:26。
      女儿:长的帅不帅?
      母亲:挺帅的。
      女儿:收入高不?
      母亲:不算很高,中等情况。
      女儿:是公务员不?
      母亲:是,在税务局上班呢。
      女儿:那好,我去见见。

这个女孩的决策过程就是典型的分类树决策。相当于通过年龄、长相、收入和是否公务员对将男人分为两个类别:见和不见。假设这个女孩对男人的要求是:30岁以下、长相中等以上并且是高收入者或中等以上收入的公务员,那么这个可以用下图表示女孩的决策逻辑:

也就是说,对未知的选项都可以归类到已知的选项分类类别中。

2、决策树描述                                                             



决策树,又称为判定树,是一种类似二叉树或多叉树的树结构。树中的每个非叶节点(包括根节点)对应于训练样本集中一个非类别属性的测试,非叶节点的每个分支对应属性的一个测试结果,每个叶子节点则代表一个类或类分布。从根节点到叶子节点的一条路径形成一条分类规则。决策树可以很方便地转化为分类规则,是一种非常直观的分类模式表示形式。决策树方法的起源是概念学习系统CLS,然后发展到ID3方法而为高潮,最后演化为能处理连续属性的C4.5。有名的决策树方法还有CART和Assistant。是应用最广的归纳推理算法之一。

决策树学习是一种归纳学习方法,当前国际上最有影响的示例学习方法首推的应当是R.Quinlan提出的ID3算法,其前身是概念学习系统CLS。ID3算法是所有可能决策树空间中一种自顶向下、贪婪的搜索方法,以信息熵的下降速度为选取测试属性的标准,即在每个节点选取还尚未被用来划分的具有最高信息增益的属性作为划分标准,然后继续这个过程,直到生成的决策树能完美分类训练样例。

在决策树构造中,如何选取一个条件属性作为形成决策树的节点是建树的核心。一般情况下,选取的属性能最大程度反映训练样本集的分类特征。ID3算法作为决策构造中的经典算法,引入了信息论的方法,应用信息论中的熵的概念,采用信息增益作为选择属性的标准来对训练样本集进行划分,选取信息增益最大的属性作为当前节点。计算信息增益还要涉及三个概念:信息熵、信息增益和信息条件熵。

信息熵

信息熵也称为香农熵,是随机变量的期望。度量信息的不确定程度。信息的熵越大,信息就越不容易搞清楚。处理信息就是为了把信息搞清楚,就是熵减少的过程。

计算香农熵的Python代码为:

#计算给定数据集的香农熵
def calcShannonEnt(dataSet):
    numEntries = len(dataSet)
    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)

    return shannonEnt

信息条件熵

(以上公式为属性A的信息条件熵)

信息增益

用于度量属性A降低样本集合X熵的贡献大小。信息增益越大,越适于对X分类。

3、ID3算法



ID3算法是决策树算法的一种。想了解什么是ID3算法之前,我们得先明白一个概念:奥卡姆剃刀。

  • 奥卡姆剃刀(Occam‘s Razor, Ockham‘s Razor),又称“奥坎的剃刀”,是由14世纪逻辑学家、圣方济各会修士奥卡姆的威廉(William of Occam,约1285年至1349年)提出,他在《箴言书注》2卷15题说“切勿浪费较多东西,去做‘用较少的东西,同样可以做好的事情’。简单点说,便是:be simple。

ID3算法(Iterative Dichotomiser 3 迭代二叉树3代)是一个由Ross Quinlan发明的用于决策树的算法。这个算法便是建立在上述所介绍的奥卡姆剃刀的基础上:越是小型的决策树越优于大的决策树(be simple简单理论)。尽管如此,该算法也不是总是生成最小的树形结构,而是一个启发式算法。

OK,从信息论知识中我们知道,期望信息越小,信息增益越大,从而纯度越高。ID3算法的核心思想就是以信息增益度量属性选择,选择分裂后信息增益(很快,由下文你就会知道信息增益又是怎么一回事)最大的属性进行分裂。该算法采用自顶向下的贪婪搜索遍历可能的决策树空间。

所以,ID3的思想便是:

  1. 自顶向下的贪婪搜索遍历可能的决策树空间构造决策树(此方法是ID3算法和C4.5算法的基础);

  2. 从“哪一个属性将在树的根节点被测试”开始;
  3. 使用统计测试来确定每一个实例属性单独分类训练样例的能力,分类能力最好的属性作为树的根结点测试(如何定义或者评判一个属性是分类能力最好的呢?这便是下文将要介绍的信息增益,or 信息增益率)。
  4. 然后为根结点属性的每个可能值产生一个分支,并把训练样例排列到适当的分支(也就是说,样例的该属性值对应的分支)之下。
  5. 重复这个过程,用每个分支结点关联的训练样例来选取在该点被测试的最佳属性。

这形成了对合格决策树的贪婪搜索,也就是算法从不回溯重新考虑以前的选择。

寻找最佳属性的Python代码:

#选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0])-1
    baseEntropy = calcShannonEnt(dataSet)                  #计算香农熵
    bestInfoGain = 0.0;bestFeature = -1
    for i in range(numFeatures):
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList)
        newEntroy = 0.0
        for value in uniqueVals:
            subDataSet = splitDataSet(dataSet, i, value)
            prop = len(subDataSet)/float(len(dataSet))
            newEntroy += prop * calcShannonEnt(subDataSet)  #计算条件信息熵
        infoGain = baseEntropy – newEntroy                   #信息增益
        if(infoGain > bestInfoGain):
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature

我们通过一个具体的例子来讲解ID3算法。主要通过两个代码文件实现。ID3决策树算法的相关操作放在文件trees.py中

# -*- coding: utf-8 -*-
‘‘‘
Created on 2015年7月27日

@author: pcithhb
‘‘‘
from math import log
import operator
#计算给定数据集的香农熵
def calcShannonEnt(dataSet):
    numEntries = len(dataSet)
    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)

    return shannonEnt

#按照给定特征划分数据集
#dataSet:待划分的数据集
#axis:划分数据集的特征--数据的第几列
#value:需要返回的特征值
def splitDataSet(dataSet,axis,value):
    retDataSet = []
    for featVec in dataSet:
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]           #获取从第0列到特征列的数据
            reducedFeatVec.extend(featVec[axis+1:])   #获取从特征列之后的数据
            retDataSet.append(reducedFeatVec)
    return retDataSet

#选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0])-1
    baseEntropy = calcShannonEnt(dataSet)
    bestInfoGain = 0.0;bestFeature = -1
    for i in range(numFeatures):
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList)
        newEntroy = 0.0
        for value in uniqueVals:
            subDataSet = splitDataSet(dataSet, i, value)
            prop = len(subDataSet)/float(len(dataSet))
            newEntroy += prop * calcShannonEnt(subDataSet)
        infoGain = baseEntropy - newEntroy
        if(infoGain > bestInfoGain):
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature
#
def majorityCnt(classList):
    classCount = {}
    for vote in classList:
        if vote not in classCount.keys():classCount[vote] = 0
        classCount[vote] += 1
    sortedClassCount = sorted(classList.iteritems(),key=operator.itemgetter(1),reverse=True)#利用operator操作键值排序字典
    return sortedClassCount[0][0]

#创建树的函数
def createTree(dataSet,labels):
    classList = [example[-1] for example in dataSet]
    if classList.count(classList[0]) == len(classList):
        return classList[0]
    if len(dataSet[0]) == 1:
        return majorityCnt(classList)
    bestFeat = chooseBestFeatureToSplit(dataSet)
    bestFeatLabel = labels[bestFeat]
    myTree = {bestFeatLabel:{}}
    del(labels[bestFeat])
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)
    for value in uniqueVals:
        subLabels = labels[:]
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)

    return myTree

#创建数据集
def createDataSetFromTXT(filename):
    dataSet = []; labels = []
    fr = open(filename)
    linenumber=0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.strip().split()
        lineset = []
        for cel in listFromLine:
            lineset.append(cel)

        if(linenumber==0):
            labels=lineset
        else:
            dataSet.append(lineset)

        linenumber = linenumber+1
    return dataSet,labels

决策树计算图形化相关操作放在treePlotter.py文件中

# -*- coding: utf-8 -*-
‘‘‘
Created on 2015年7月27日

@author: pcithhb
‘‘‘
import matplotlib.pyplot as plt

decisionNode = dict(boxstyle="sawtooth", fc="0.8")
leafNode = dict(boxstyle="round4", fc="0.8")
arrow_args = dict(arrowstyle="<-")

#获取叶节点的数目
def getNumLeafs(myTree):
    numLeafs = 0
    firstStr = myTree.keys()[0]
    secondDict = myTree[firstStr]
    for key in secondDict.keys():
        if type(secondDict[key]).__name__==‘dict‘:#测试节点的数据是否为字典,以此判断是否为叶节点
            numLeafs += getNumLeafs(secondDict[key])
        else:   numLeafs +=1
    return numLeafs

#获取树的层数
def getTreeDepth(myTree):
    maxDepth = 0
    firstStr = myTree.keys()[0]
    secondDict = myTree[firstStr]
    for key in secondDict.keys():
        if type(secondDict[key]).__name__==‘dict‘:#测试节点的数据是否为字典,以此判断是否为叶节点
            thisDepth = 1 + getTreeDepth(secondDict[key])
        else:   thisDepth = 1
        if thisDepth > maxDepth: maxDepth = thisDepth
    return maxDepth

#绘制节点
def plotNode(nodeTxt, centerPt, parentPt, nodeType):
    createPlot.ax1.annotate(nodeTxt, xy=parentPt,  xycoords=‘axes fraction‘,
             xytext=centerPt, textcoords=‘axes fraction‘,
             va="center", ha="center", bbox=nodeType, arrowprops=arrow_args )

#绘制连接线
def plotMidText(cntrPt, parentPt, txtString):
    xMid = (parentPt[0]-cntrPt[0])/2.0 + cntrPt[0]
    yMid = (parentPt[1]-cntrPt[1])/2.0 + cntrPt[1]
    createPlot.ax1.text(xMid, yMid, txtString, va="center", ha="center", rotation=30)

#绘制树结构
def plotTree(myTree, parentPt, nodeTxt):#if the first key tells you what feat was split on
    numLeafs = getNumLeafs(myTree)  #this determines the x width of this tree
    depth = getTreeDepth(myTree)
    firstStr = myTree.keys()[0]     #the text label for this node should be this
    cntrPt = (plotTree.xOff + (1.0 + float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff)
    plotMidText(cntrPt, parentPt, nodeTxt)
    plotNode(firstStr, cntrPt, parentPt, decisionNode)
    secondDict = myTree[firstStr]
    plotTree.yOff = plotTree.yOff - 1.0/plotTree.totalD
    for key in secondDict.keys():
        if type(secondDict[key]).__name__==‘dict‘:#test to see if the nodes are dictonaires, if not they are leaf nodes
            plotTree(secondDict[key],cntrPt,str(key))        #recursion
        else:   #it‘s a leaf node print the leaf node
            plotTree.xOff = plotTree.xOff + 1.0/plotTree.totalW
            plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)
            plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))
    plotTree.yOff = plotTree.yOff + 1.0/plotTree.totalD

#创建决策树图形
def createPlot(inTree):
    fig = plt.figure(1, facecolor=‘white‘)
    fig.clf()
    axprops = dict(xticks=[], yticks=[])
    createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)    #no ticks
    #createPlot.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses
    plotTree.totalW = float(getNumLeafs(inTree))
    plotTree.totalD = float(getTreeDepth(inTree))
    plotTree.xOff = -0.5/plotTree.totalW; plotTree.yOff = 1.0;
    plotTree(inTree, (0.5,1.0), ‘‘)
    plt.show()

假设在核电站运行过程中,判断某类事故发生与不发生,而事故时由各种部件的故障特征表现出来的,为了简单,我们假设训练集包含10条元素(存放于文件dataset.txt)。其中T1-T6表示各部件的值,Y1表示某种事故,1-表示发生,0-表示不发生

我们先通过从文件加载到数据集中,然后计算数据集的信息熵

# -*- coding: utf-8 -*-
‘‘‘
Created on 2015年7月27日

@author: pcithhb
‘‘‘
import trees
import treePlotter

if __name__ == ‘__main__‘:
    pass

myDat,labels = trees.createDataSetFromTXT("dataset.txt")

shan = trees.calcShannonEnt(myDat)
print shan

结果为:0.881290899231

然后通过计算信息增益,得到第一次最佳的分割属性:

col = trees.chooseBestFeatureToSplit(myDat)
print col

结果为:4,意味着最佳的分割属性为T5.

最后通过构建决策树,

Tree = trees.createTree(myDat, labels)
print Tree

treePlotter.createPlot(Tree)

结果为:{‘T5‘: {‘0.25‘: {‘T1‘: {‘0.5‘: ‘0‘, ‘0.75‘: ‘1‘}}, ‘0.5‘: ‘0‘, ‘0.75‘: ‘0‘}}

图形化的结果图为:

时间: 2024-10-09 02:57:13

数据挖掘之决策树的相关文章

Python数据挖掘—分类—决策树

概念 决策树(Decision Tree):它通过对训练样本的学习,并建立分类规则,然后依据分类,对新样本数据进行分类预测,属于有监督学习 优点:决策树易于理解和实现,决策树可处理数值型和非数值型数据 步骤 导入数据,确定虚拟变量的列,然后遍历这些列,将这些类的数据转换为分类型数据,再通过get_dummies()方法获取虚拟变量 1 import pandas 2 3 data=pandas.read_csv( 4 "C:\\Users\\Jw\\Desktop\\python_work\\P

数据挖掘(三)——决策树

一.概念 一张图就可以理解决策树是什么 图中的属性有三种:No Surfacing (水下是否可生存).Filppers(有无脚蹼).Fish(鱼),通常我们通过前两个属性来判断第三个属性,判断到底是不是鱼.所以 第三个属性这里就称它为决策属性 二.构建决策树的基本步骤 1.将所有数据看作是一个节点 2.计算信息熵选择出最好的分割点(如图中的No Surfacing或Filppers) 3.分割数据(假如分成两份数据子集A和B),看数据子集中的决策属性是否相同,相同则不继续分 4.不相同则继续分

【Python数据挖掘】决策树

决策树的定义 决策树(decision tree)是一个树结构(可以是二叉树或非二叉树).其每个非叶节点表示一个特征属性上的测试,每个分支代表这个特征属性在某个值域上的输出,而每个叶节点存放一个类别.使用决策树进行决策的过程就是从根节点开始,测试待分类项中相应的特征属性,并按照其值选择输出分支,直到到达叶子节点,将叶子节点存放的类别作为决策结果. 树是由节点和边两种元素组成的结构.理解树,就需要理解几个关键词:根节点.父节点.子节点和叶子节点. 父节点和子节点是相对的,说白了子节点由父节点根据某

数据挖掘之决策树ID3算法(C#实现)

决策树是一种非常经典的分类器,它的作用原理有点类似于我们玩的猜谜游戏.比如猜一个动物: 问:这个动物是陆生动物吗? 答:是的. 问:这个动物有鳃吗? 答:没有. 这样的两个问题顺序就有些颠倒,因为一般来说陆生动物是没有鳃的(记得应该是这样的,如有错误欢迎指正).所以玩这种游戏,提问的顺序很重要,争取每次都能够获得尽可能多的信息量. AllElectronics顾客数据库标记类的训练元组 RID age income student credit_rating Class: buys_comput

决策树代码(转)

转自http://blog.csdn.net/fy2462/article/details/31762429 一.前言 当年实习公司布置了一个任务让写一个决策树,以前并未接触数据挖掘的东西,但作为一个数据挖掘最基本的知识点,还是应该有所理解的. 程序的源码可以点击这里进行下载,下面简要介绍一下决策树以及相关算法概念. 决策树是一个预测模型:他代表的是对象属性与对象值之间的一种映射关系.树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每个叶结点则对应从根节点到该叶节点所经历的路

数据挖掘之分类和预测

分类用于预测数据对象的离散类别,预测则用于预断 欺诈检测等的方面. 具有代表性的分类的方法 :决策树方法 贝叶斯分类方法 神经网络方法 支持向量机方法 关联分类的方法 最后 将讨论提高分类和预测期准确率的一般性的策略 分类的过程一般是有两个步骤组成的 第一个步骤是模型建立阶段,目的是描述预先定义的数据类或者概念集的分类器.这一步中会使用分类算法分析已有数据来构造分类器. 第二步骤是使用第一步得到的分类器进行分类,从而评估分类器的预测的准确率 预测与分类不同的是 对于需要预测的属性值是连续的 ,而

机器学习—— 决策树(ID3算法)的分析与实现

KNN算法请参考:http://blog.csdn.net/gamer_gyt/article/details/47418223 一.简介         决策树是一个预测模型:他代表的是对象属性与对象值之间的一种映射关系.树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每个叶结点则对应从根节点到该叶节点所经历的路径所表示的对象的值.决策树仅有单一输出,若欲有复数输出,可以建立独立的决策树以处理不同输出. 数据挖掘中决策树是一种经常要用到的技术,可以用于分析数据,同样也可以用

二叉树的算法与讲法

二叉树属于数据结构中层次性的数据关系,他又祖先--后代,上级--下属,整体--部分以及其他类似的关系,树结构在计算机领域中有着广泛的应用,例如在编译程序中庸语法树来表示元程序的语言结构,在数据挖掘中庸决策树来进行数据分类等等.在我的前一个博客中也有提到就是二叉树的相关知识重点.不清楚的同行可以参考我的文章.其中若有不妥之处,还请大家指点. 下面是我在学习二叉树的时候编写的二叉树的几个常见的功能的函数,以及他的一些构造函数等等. #ifndef BITREE_H #define BITREE_H

FPGA机器学习之机器学习的n中算法总结2

前面已经说了很多的算法了.比如说退火算法,蚂蚁算法,文化算法,禁忌算法等等.接下来要写一些其他的机器学习算法.迁移学习,集成算法,向量机,在线学习等算法. 我毛华望QQ849886241.技术博客http://blog.csdn.net/my_share 迁移学习算法:大概理解一下就是,机器学习了一些知识后,可以更容易学会其他的知识,举个例子,学会桌子的人,更容易学会认识椅子.学会下象棋的人,更容易学围棋.基于boosting的迁移学习算法.http://wenku.baidu.com/link