决策树从原理到算法的实现

基本步骤流程 :

  1. 计算给定数据的原始熵
  2. 划分数据集
  3. 选择最好的特征划分数据集
  4. 构建树的结构
  5. 使用决策树执行分类
  6. 决策树的存储和调用
  7. 绘制树形图

决策树:是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶子节点代表一种类别。

  • 优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以知道哪些特征重要哪些不太重要
  • 缺点:可能会产生过度匹配问题
树结构

                                                    

划分数据的原则是:将无序的数据变得更加有序。那么怎么衡量一堆数据的混乱程度呢,信息论之父克劳德.香农提出了熵,也叫作香农熵。计算公式为H = -\sum p_{x_{i}}.log_{2}p_{x_{i}},当为确定事件时,即概率为0或1时,熵都为0,说明此时数据是有序的,类别是确定的。

信息增益 = 原始熵 - 划分后数据熵,信息增益越大,说明划分后数据熵越小,即划分后数据更有序, 说明这个特征越好越重要,越能够分类。 

克劳德.香农被公认为是二十世纪最聪明的人之一,贝尔实验室和MIT有很多人将香农和爱因斯坦相提并论,而其他人则认为这种对比是不公平的——对香农是不公平的。熵这个词其实是冯.诺依曼建议使用的,他建议的理由是因为大家从来没听过这个词,不知道它是什么意思。 

下面以海洋生物数据为例,实现决策树从原理到算法的实现: 

                                                                                                      海洋生物数据

  不浮出水面是否可以生存 是否有脚蹼 是否属于鱼类
1
2
3
4
5

 1.计算给定数据的原始熵

import numpy as np
import math
from math import log
def shannonEntropy(dataSet):
    num = len(dataSet)
    classCount = {}
    for a in dataSet:
        label = a[-1]#最后一列为类别标签
        classCount[label] = classCount.get(label,0)+1
    shangnon = 0.0
    for key in classCount:
        prob = float(classCount[key])/num
        shangnon += -prob*log(prob,2)#香农熵计算公式
    return shangnon

dataSet = [[1,1,'yes'],
          [1,1,'yes'],
          [1,0,'no'],
          [0,1,'no'],
          [0,1,'no']]
shangnon = shannonEntropy(dataSet)
shangnon
运行结果:0.9709505944546686

2.划分数据集

def splitDataSet(dataSet,feature_index,feature_value):
    subDataSet = []
    for b in dataSet:
        if b[feature_index]==feature_value:
            temp = b[:feature_index]#注意这里不能直接用del删除而应该用切片,用del原数据集会改变
            temp.extend(b[feature_index+1:])
            subDataSet.append(temp)
    return subDataSet

splitDataSet(dataSet,0,1)#以第一个特征划分,如果数据集中样本第一个特征为1,则去掉第一个特征,保留其它特征和类别标签

运行结果:[[1, 'yes'], [1, 'yes'], [0, 'no']]

3.选择最好的特征划分数据集(即选择根节点)

def selectRootNode(dataSet):
    baseEntropy = shannonEntropy(dataSet)#计算原始香农熵
    numFeatures = len(dataSet[0])-1#特征个数
    maxInfoGain = 0.0;bestFeature = 0
    for i in range(numFeatures):
        featList = [example[i] for example in dataSet]
        uniqVals = set(featList)
        newEntropy = 0.0
        for j in uniqVals:
            subDataSet = splitDataSet(dataSet,i,j)
            prob = len(subDataSet)/float(len(dataSet))
            newEntropy += prob * shannonEntropy(subDataSet)
        infoGain = baseEntropy - newEntropy#信息增益
        if(infoGain>maxInfoGain):
            maxInfoGain = infoGain
            bestFeature = i
    return bestFeature

selectRootNode(dataSet)
运行结果:0

4.构建树的结构

def createTree(dataSet,labels):
    classList = [example[-1] for example in dataSet]
    if classList.count(classList[0]) == len(classList):
        return classList[0]
    bestFeat = selectRootNode(dataSet)
    bestFeatLabel = labels[bestFeat]
    myTree = {bestFeatLabel:{}}
    del labels[bestFeat]
    featValues = [example[bestFeat] for example in dataSet]
    uniqValues = set(featValues)
    for i in uniqValues:
        subLabels = labels[:]
        myTree[bestFeatLabel][i] = createTree(splitDataSet(dataSet,bestFeat,i),subLabels)
    return myTree

labels = ['no surface','flippers']
myTree = createTree(dataSet,labels)
myTree
运行结果:{'no surface': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

5.使用决策树执行分类

def classifier(myTree,featLabels,testVec):
    firstFeat = list(myTree.keys())[0]
    secondDict = myTree[firstFeat]
    featIndex = featLabels.index(firstFeat)
    for key in secondDict.keys():
        if testVec[featIndex] == key:
            if type(secondDict[key]).__name__ == 'dict':
                classLabel = classifier(secondDict[key],featLabels,testVec)
            else:classLabel = secondDict[key]
    return classLabel 

featLabels = ['no surface','flippers']
testVec = [1,0]
classifier(myTree,featLabels,testVec)
运行结果:'no'

6.决策树 的存储和调用

构造决策树是很耗时的任务,而用创建好的决策树来处理分类问题,则可以很快完成。因此,为了节约时间,将构造好的决策树保存起来,下次用的时候直接导进来调用就好了

#使用pickle模块将树结构保存成文件
def storeTree(myTree,filename):
    import pickle
    fw = open(filename,'wb')#以二进制形式写
    pickle.dump(myTree,fw)
    fw.close()
# 使用pickle模块导入树结构文件 
def grabTree(filename):
    import pickle
    fr = open(filename,'rb')#以二进制形式读
    return pickle.load(fr)

storeTree(myTree,'myTree.txt')
grabTree('myTree.txt')
运行结果:{'no surface': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

7.绘制树形图

7.1画sklearn包中自带的iris数据集的树形图

from sklearn.datasets import load_iris
from sklearn import tree
clf = tree.DecisionTreeClassifier()
iris = load_iris()
clf = clf.fit(iris.data, iris.target)

安装Graphviz

#下载网站:http://www.graphviz.org/Download

#添加环境变量在系统环境变量path中将Graphviz的bin的目录路径添加上

#如果我们安装了Python模块pydotplus,我们可以直接在Python中生成PDF文件(或任何其他支持的文件类型)

#安装pydotplus在Anaconda Prompt中输入:conda install -c conda-forge pydotplus

#将树形图生成PDF文件
import pydotplus
dot_data = tree.export_graphviz(clf, out_file=None)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_pdf("iris.pdf")
iris数据集树形图
#通过Ipython生成渲染的树形图
from IPython.display import Image 
dot_data = tree.export_graphviz(clf, out_file=None,
                         feature_names=iris.feature_names, 
                         class_names=iris.target_names, 
                         filled=True, rounded=True, 
                         special_characters=True) 
graph = pydotplus.graph_from_dot_data(dot_data) 
Image(graph.create_png())

7.2.绘制海洋生物数据的树形图

#由上面例子画海洋生物数据树形图
from sklearn import tree
clf = tree.DecisionTreeClassifier()
data = np.array([[1,1],[1,1],[1,0],[0,1],[0,1]])
target =np.array(['yes','yes','no','no','no'])
clf = clf.fit(data,target)
import pydotplus
dot_data = tree.export_graphviz(clf, out_file=None)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_pdf("fish.pdf")
海洋生物数据树形图
#仿照iris画海洋生物数据的渲染树形图
from IPython.display import Image 
dot_data = tree.export_graphviz(clf, out_file=None, 
                         feature_names=['no face','flipper'], 
                         class_names = ['no','yes'],
                         filled=True, rounded=True, 
                         special_characters=True) 
graph = pydotplus.graph_from_dot_data(dot_data) 
Image(graph.create_png())

猜你喜欢

转载自blog.csdn.net/qq_24946843/article/details/83902955
今日推荐