决策树算法以及个人经历吐槽

本文分享了作者在紧张的科研任务之余,坚持学习并实践决策树算法的经历。文章详细介绍了使用Python实现决策树算法的过程,包括关键函数的解析、决策树的绘制及应用案例。
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"><span style="white-space:pre">	</span>前段时间,好长一段时间,老师抓着他的项目不放,整日在写程序,进行程序加速,好累啊,可能自己现在想多学点感兴趣的东西,为自己以后打算。本来计划的每周起码</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">一篇博客的计划,被老师的基金给冲散了,伤心,不知道</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">不久的将来还会不会有什么基金来,人的精力是有限的这句话此处说来简直让人动容,看来往后准备博客的时间起码要在晚上 12 点以后了,关实验的意义方面,我也思考了好久,</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">到底有没有必要在这里花费巨大的精力完成一项看似没有什么立即可以对像什么基金什么项目产生现实的立即作用的工作,可能是我思考这个问题的时候是先入为主的觉得自己应</span>

该坚持做下去,所以我觉得我写这些东西还是有意义的,起码对于自己对知识的理解有了阶段性的总结,对以后有缘看到此文的人的学习也会有很大帮助,具体的意义我没有时间在这里深入讨论,反正我现在是要坚持做下去的。发了那么多的牢骚,徒劳……

好了好了,抱怨到此为止。

决策树算法实验:
自己在看这章的算法的时候,有个语句做了好几个实验才理解了作用,可能是自己的 python 是半路出家的缘故吧
我在这里给大家解释一下这个程序,免得读者跟自己一样在这些基础问题上的疑问影响最学习进度:

def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0]) - 1      #the last column is used for the labels
    baseEntropy = calcShannonEnt(dataSet)
    bestInfoGain = 0.0; bestFeature = -1
    for i in range(numFeatures):        #iterate over all the features
        featList = [example[i] for example in dataSet]#create a list of all the examples of this feature
        uniqueVals = set(featList)       #get a set of unique values
        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     #calculate the info gain; ie reduction in entropy
        if (infoGain > bestInfoGain):       #compare this to the best gain so far
            bestInfoGain = infoGain         #if better than current best, set to best
            bestFeature = i
    return bestFeature                      #returns an integer
注意这里的:

featList = [example[i] for example in dataSet]
这个循环是每一次都可以取到 myDat 的所有数据的第一维特征的数值,我在第一次循环中打印出 fearList 的值此时,它已经是所有样本的某一维特征的数值了,请看以下实验结果:

myDat = [ [1,2,'a'],[3,4,'b'],[4,5,'c'] ]
for i in range(3):
    featList = [feat[i] for feat in myDat]
此句的输出为下方结果:

>>> featList
['a', 'b', 'c']
所以请不理解程序语句的时候立马做上几个实验看一下自己的想法是不是正确的,毕竟自己做出来的理解才深刻。

下面使用 python 构建简单的决策树的简单实验(新建的 myPlot,py):

# 这是我新建的简单的决策树建立代码
import matplotlib.pyplot as plt

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

def plotNode(nodeTxt, centerPt, parentPt, nodeType):
    createPlot_1.ax1.annotate(nodeTxt, xy=parentPt,  xycoords='axes fraction',
             xytext=centerPt, textcoords='axes fraction',
             va="center", ha="center", bbox=nodeType , arrowprops=arrow_args)#
	
def createPlot_1():
    fig = plt.figure(1, facecolor='white')
    fig.clf()
    createPlot_1.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses 
    plotNode('a decision node', (0.5, 0.1), (0.1, 0.5), decisionNode)
    plotNode('a leaf node', (0.8, 0.1), (0.3, 0.8), leafNode)
    plt.show()
本代码的输出图像为:


这是基本的 matplotlib 使用方法,本文后附上 matplotlib  学习网址。

在学习完了决策树的知识之后,就可以往下做实验了,本章的决策树学习算法为 ID3,其实 ID3 与 ID4.5 在使用上的差距并不大,只不过是 ID3 在特征选取上使用的是信息增益,而 ID4.5 使用的是信息增益比,信息增益比可以有效的避免因为一个特征的数量过大而造成的其他特征被淹没的风险,决策树的生成使用的是递归生成,依靠 python数据结构中字典的这一特殊结构,可以直接在既生成的决策树上添加新生成的树,算法的具体实现如下(构造决策树文件为  treePlotter.py):

# treePlotter.py 文件,文件引用的是机器学习实战源代码
'''
Created on Oct 14, 2010

@author: Peter Harrington
'''
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':#test to see if the nodes are dictonaires, if not they are leaf nodes
            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':#test to see if the nodes are dictonaires, if not they are leaf nodes
            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
#if you do get a dictonary you know it's a tree, and the first element will be another dict

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()

def createPlot_1():
    fig = plt.figure(1, facecolor='white')
    fig.clf()
    createPlot_1.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses 
    plotNode('a decision node', (0.5, 0.1), (0.1, 0.5), decisionNode)
    plotNode('a leaf node', (0.8, 0.1), (0.3, 0.8), leafNode)
    plt.show()

def retrieveTree(i):
    listOfTrees =[{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}},
                  {'no surfacing': {0: 'no', 1: {'flippers': {0: {'head': {0: 'no', 1: 'yes'}}, 1: 'no'}}}}
                  ]
    return listOfTrees[i]

#createPlot(thisTree)

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">	</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">现在添加数据就可以完成决策树的构造了,完整的决策树如下图:</span>


不过貌似有点突兀,所以再添加一个数据,让树起码有三个叉啊:

>>> myTree['no surfacing'][3] = 'maybe'
>>> treePlotter.createPlot(myTree)
>>> myTree = treePlotter.retrieveTree(0)
>>> treePlotter.createPlot(myTree)
三个叉的树看着还是可以得吧:



对文中的关于隐形眼镜类型的预测实验只需要打开文件,读入数据:

>>> numFile = open('lenses.txt')
>>> lenses = [inst.strip().split('\t') for inst in numFile.readlines()]
>>> lensesLables = ['age','prescript','astigmatic','tearRate']
>>> import trees
>>> lensesTree = trees.createTree(lenses,lensesLables)
>>> treePlotter.createPlot(lensesTree)
最后构建的决策树就有点复杂了:



这是逃脱编写老板基金算法代码的第一篇,全部靠记忆写的,可能会有疏漏,看到的童鞋麻烦指正哦,谢谢。

附:python 下matplotlib的入门指导,学习如何画图还是很重要的,这样可以使人对你的数据有清晰直观的了解。

Matplotlib Tutorial(这是译文版,翻译的很好,特别适合英语不好的汉子们)

最近还在考虑写自己对机器学习理论的理解的那个板块的文章,这个版本只是重复做实验加深理解,自己也在想是不是可以两个板块同时写,这样每周最少两篇的博客是不是时间有点紧呢,纠结…………祝好。

这周确实遇到了很多很多不开心的事情,还好我是有文艺范的工科男,一直拿银翼杀手里面那句灰常经典的话来安慰自己,这里也送给大家,谁都遇到过让自己愤怒,伤心或是不知所措的事情,安慰自己一下,这都会过去的,看的开一点:

All those moments will be lost in time, like tears...in...rain.


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值