机器学习算法之决策树(python)

来源:互联网 发布:excel提取网页数据 编辑:程序博客网 时间:2024/04/30 05:39

决策树算法通过对历史数据进行测算实现对新数据进行分类和预测。决策树算法就是通过对已有明确结果的历史数据进行分析,寻找数据中的特征,并以此为依据对新产生的数据结果进行预测。决策树的3个主要部分分别为:决策节点,分支和叶子节点。其中决策树最顶部的决策节点是根决策节点,每一个分支都有一个新的决策节点,决策节点下面是叶子节点。每个决策节点表示一个待分类的数据类别或属性,每个叶子节点表示一种结果。整个决策的过程从根决策节点开始,从上到下。根据数据的分类在每个决策节点给出不同的结果。


划分数据集的最大原则是:使无序的数据变的有序。如果一个训练数据中有20个特征,那么选取哪个做划分依据?这就必须采用量化的方法来判断,量化划分方法有多重,其中一项就是“信息论度量信息分类”。基于信息论的决策树算法有ID3、CART和C4.5等算法,其中C4.5和CART两种算法从ID3算法中衍生而来。构造决策树的方法有很多种,ID3是其中的一种算法。ID3算法核心是“信息熵”。ID3算法认为“互信息”高的属性是好属性,通过计算历史数据中每个类别或属性的“信息熵”获得“互信息”,并选择“互信息”最高的类别或属性作为决策树中的决策节点,将类别或属性的值做为分支继续进行分裂。不断重复这个过程,直到生成一棵完整的决策树。

信息熵是衡量信息的不确定性或混乱程度的指标。信息的不确定性越大,熵越大。决定信息的不确定性或者说复杂程度主要因素是概率。决策树中使用的与熵有关的概念有三个:信息熵,条件熵和互信息。例如抛硬币,可能出现的结果有两个,分别是正面和反面。而每次抛硬币的结果是一个非常不确定的信息。因为根据我们的经验或者历史数据来看,一个均匀的硬币出现正面和反面的概率相等,都是50%。因此很难判断下一次出现的是正面还是反面。这时抛硬币这个事件的熵值也很高。而如果历史数据告诉我们这枚硬币在过去的100次试验中99次都是正面,也就是说这枚硬币的质量不均匀,出现正面结果的概率很高。那么我们就很容易判断下一次的结果了。这时的熵值很低,只有0.08。若待分类的事物可能划分在N类中,分别是x1,x2,……,xn,每一种取到的概率分别是P1,P2,……,Pn,那么X的熵就定义为:


python实现参照机器学习实战:

新建trees.py文件

from math import logdef calcShannonEnt(dataSet):      #calculate the shannon value      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  def createDataSet():    #create dataset    dataSet=[[1,1,'yes'],             [1,1,'yes'],             [1,0,'no'],             [0,1,'no'],             [0,1,'no']]    labels=['no surfacing','flippers']    return dataSet,labels

在shell里执行:

>>> reload(trees)<module 'trees' from 'trees.py'>>>> myDat,labels=trees.createDataSet()>>> myDat[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]>>> trees.calcShannonEnt(myDat)0.9709505944546686
在trees.py文件中继续写入函数:

def splitDataSet(dataSet,axis,value):    #splite dataset    retDataSet=[]    for featVec in dataSet:        if featVec[axis]==value:            reducedFeatVec=featVec[:axis]            reducedFeatVec.extend(featVec[axis+1:])            retDataSet.append(reducedFeatVec)    return retDataSetdef chooseBestFeatureToSplit(dataSet):    #choose the best splite method by Shannon Value,choose the biggest    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)          newEntropy = 0.0          for value in uniqueVals:              subDataSet = splitDataSet(dataSet, i , value)              prob = len(subDataSet)/float(len(dataSet))              newEntropy +=prob * calcShannonEnt(subDataSet)          infoGain = baseEntropy - newEntropy          if(infoGain > bestInfoGain):              bestInfoGain = infoGain              bestFeature = i      return bestFeature
在shell中执行:

>>> reload(trees)<module 'trees' from 'trees.py'>>>> myDat,labels=trees.createDataSet()>>> trees.splitDataSet(myDat,0,1)[[1, 'yes'], [1, 'yes'], [0, 'no']]>>> trees.splitDataSet(myDat,0,0)[[1, 'no'], [1, 'no']]>>> trees.chooseBestFeatureToSplit(myDat)0
执行结果表明:第0个特征更能适用于分类判断。
在trees.py文件中继续写入(首行添加一句:import operator):

def majorityCnt(classList):    #return the feather which appear most    classCount = {}      for vote in classList:          if vote not in classCount.keys():            classCount[vote] = 0          classCount[vote] += 1      sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)      return sortedClassCount[0][0]  def createTree(dataSet, labels):      classList = [example[-1] for example in dataSet]      # if the type is the same, stop classify      if classList.count(classList[0]) == len(classList):          return classList[0]      # traversal all the features and choose the most frequent feature      if (len(dataSet[0]) == 1):          return majorityCnt(classList)      bestFeat = chooseBestFeatureToSplit(dataSet)      bestFeatLabel = labels[bestFeat]      myTree = {bestFeatLabel:{}}      del(labels[bestFeat])      #get the list which attain the whole properties      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  

在shell中执行:

>>> myTree=trees.createTree(myDat,labels)>>> myTree{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
训练好的数据最终的目的是进行分类,在trees.py中继续写入:

def classify(inputTree, featLabels, testVec):    #use to classify new feather    firstStr = inputTree.keys()[0]      secondDict = inputTree[firstStr]      featIndex = featLabels.index(firstStr)      for key in secondDict.keys():          if testVec[featIndex] == key:              if type(secondDict[key]).__name__ == 'dict':                  classLabel = classify(secondDict[key], featLabels, testVec)              else: classLabel = secondDict[key]      return classLabel  

在shell中执行:

>>> myDat,labels=trees.createDataSet()>>> labels['no surfacing', 'flippers']>>> trees.classify(myTree,labels,[1,0])'no'>>> trees.classify(myTree,labels,[1,1])'yes'

另外,在网上也能找到C++实现的决策树算法,见参考部分。

参考:

《机器学习实战》

http://www.tuicool.com/articles/fMvyeq (PYTHON)

http://blog.csdn.net/tianzhaixing2013/article/details/37053603 (PYTHON)

http://blog.sina.com.cn/s/blog_8095e51d01013chj.html  

http://blog.csdn.net/czp11210/article/details/51161531

http://blog.csdn.net/yangliuy/article/details/7322015  (C++)

http://blog.csdn.net/zhoubl668/article/details/40828573 (C++)

http://www.voidcn.com/blog/zhaocj/article/p-4978286.html (Opencv)

0 0
原创粉丝点击