Python机器学习实战(二)--决策树

来源:互联网 发布:淘宝五金店铺介绍 编辑:程序博客网 时间:2024/05/14 06:00

Python机器学习实战(二)--决策树

 

         决策树是处理分类问题的一个非常直观的算法,决策树是一个类似流程图的树结构,树中的每个内部节点是一个特征的测试,每个分支是一个特性输出,每一个叶子节点是数据所属的一个类型。如下图结构(图片来源网络,仅供学习参考)

 

 

图中橙色节点即为数据类型:见,不见。

绿色节点表示对数据的某一特征进行测试,即对年龄,长相,收入,公务员几个特征进行测试。

每一个分支即表示了特征的具体值,即年龄值<=30>30

 

 

年龄是否大于30

长相是否丑

收入(高:1,中:0,低:-1

是否公务员

选择见面还是不见面

1

1

1

0

1

0

2

1

0

1

0

0

3

0

1

-1

0

0

4

0

0

1

0

1

5

0

1

0

1

0

6

0

0

0

1

1

7

0

0

0

0

0

 

以上是一个训练集示例。可以对应创建一个简单数据集。

 

决策树算法通过训练集确定一个最优的决策树。

 

 

 

 

下面介绍如何构造决策树

决策树的构造流程如下面伪代码所示

CreateBranch():

检测数据集中每一子项是否属于同一分类:

         Ifture return 类标签

         Else

                   继续划分数据集

                   创造分支节点

                            For每个划分的子集

                                    调用函数CreateBranch并增加结果到分支节点

                   Return分支节点

 

即判断数据子集是否分类完成,否的话,对每个数据子集继续进行划分。

这里显然可以看到一个问题:对一个数据集分割时,应该选择哪一个特性进行划分?

 

 

下面介绍选择最优划分特性的方法:

依据信息论的理论基础,划分数据集的大原则是:将无序的数据变得更加有序。

那么如何度量是否有序,即通过计算数据信息的香农熵

熵定义为信息的期望值,对一个数据集的每一个类型x的信息定义为:

L(x) = - log p(x)

P(x)为特征值为x的概率。

熵值即为所有类别的信息期望值:

H = -sum( p(x)*log p(x) )

即对每一个特征值计算- p(x) * L(x),然后求和。

 

下面代码给出了计算一个数据集的香农熵

 

def calcShannonEnt(dataSet):            #计算香农熵 dataSet为数据集    numEntries = len (dataSet)          #计算特征数    labelCounts = {}                    #创建一个类型:类型值的字典    for featVet in dataSet:        currentlabel = featVet[-1]      #选取类型值        labelCounts[currentlabel] = labelCounts.get(currentlabel,0)+1    shannonEnt = 0.0                    #初始化香农熵    for key in labelCounts:             #对每个类型计算        prob = float(labelCounts[key])/numEntries        shannonEnt -= prob*log(prob,2)    return shannonEnt

 

 

知道了划分的标准,下面就可以给出选择最好划分集的方式:

先给出一个划分函数,该函数对输入的指定数据集,划分特征,特征值,返回对应的数据子集,同时返回的数据子集中已删除输入特征这一信息。

代码如下:

def splitDataSet(dataSet,axis,value):           #分割数据集dataSet,返回第axis个特征值为value,同时删除该特征的数据    retDataSet = []    for featVet in dataSet:        if featVet[axis] == value:              #判断第axis个特征是否为value            reducedFeatVec = featVet[:axis]            reducedFeatVec.extend(featVet[axis+1:])         #删除第axis个特征            retDataSet.append(reducedFeatVec)               #将选择处理过的数据加入结果    return retDataSet

 

 

最好划分函数,该函数对输入数据集返回一个最好特征的索引值,基本思想即遍历每一个特征,比较划分后的香农熵,选出最小值即可。

代码如下:

 

def chooseBestFeatureToSplit(dataSet):          #从dataSet数据集中选择最优的特性,返回特征的索引    numFeatures = len(dataSet[0])-1             #计算特征数    baseEntropy = calcShannonEnt(dataSet)       #计算初始数据香农熵    bestInfoGain = 0.0                          #熵能减小的最大值    bestFeature = -1                            #初始化最优特征索引为-1    for i in range(numFeatures):                #对每一个特征计算分割后的香农熵        newEntropy = 0.0        for example in dataSet:            featList = [example[i]]             #第i个特征的所有值的列表        uniqueVals = set(featList)              #用集合表示第i个特征值的集合        for value in uniqueVals:                subDataSet = splitDataSet(dataSet,i,value)            prob = float(len(subDataSet))/len(dataSet)            newEntropy += prob * calcShannonEnt(subDataSet)        infoGain = baseEntropy - newEntropy        if (infoGain > bestInfoGain):            bestInfoGain = infoGain            bestFeature = i       return bestFeature

 

 

 

 

另外针对对所有特征进行划分完后,数据依然不是同一个类别时,我们可以选择返回类别数最多的类别,如下面的函数所示:

 

def majorityCnt(classList):    classCount = collections.defaultdic(int)    for vote in classList:        classCount[vote] += 1    sortedclassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=Ture)    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)    bestFeature = chooseBestFeatureToSplit(dataSet)    bestFeatureLabel = labels[bestFeature]    myTree = {bestFeatureLabel:{}}    del(labels[bestFeature])    featureValues = [example[bestFeature] for example in dataSet]    uniqueValues = set(featureValues)    for value in uniqueValues:        subLabels = labels[:]        myTree[bestFeatureLabel][value] = createTree(splitDataSet(dataSet,bestFeature,value),subLabels)    return myTree

 

 

以上就是构建一个决策树的过程

 

下面给出一个简单的测试,利用该决策树对数据进行分类

输入参数为决策树,特征标签列表,待分类数据,返回类别

函数中由决策树确定每次划分特征,可以通过对特征标签列表用index方法返回索引,进行确定数据中该特征的值。

代码如下:

def classify(inputTree,featLabels,testVec):    firstStr = inputTree.keys()[0]    secondDict = inputTree[firstStr]    featIndex = featLabels.index(firstStr)    key = testVec[featIndex]    valueOfFeat = secondDict[key]    if isinstance(valueOfFeat, dict):         classLabel = classify(valueOfFeat, featLabels, testVec)    else: classLabel = valueOfFeat    return classLabel

以上为决策树的一些主要内容


0 0