python3机器学习实战之decisionTree大坑

版权声明:如有雷同,不甚荣幸 https://blog.csdn.net/Fengyutianqing/article/details/82178001

入了机器学习的大坑之后,最近跟着《机器学习实战》学到决策树

我用的jupyter

代码敲到creatTree卡住了。

返回检查前面的代码,函数一个一个的查,最后得出结论,没问题啊!!!可是问题还是没有解决

报错原因如上,我实在是按书上的敲的,奈何就是进行不下去,之后在网上找了一大堆这一章的代码copy还是不行,这特么是怎么了 ??

之后我想我把代码贴到pycharm中,找错误应该好找些,然后我把代码贴到pycharm中运行,居然成功运行了

我在想这难道是编译器的问题,

睡了一觉起来感觉还是不对,都是python3,怎么可能?

找网上的关于list out of range的相关文章

参考https://blog.csdn.net/cckchina/article/details/79776572

而这个兄弟的报错问题则是这个

参考https://bbs.csdn.net/topics/392427506

然而对于我这个菜鸟,这些大神的思路我还是跟不上,上面的没有返回值,明明有return啊,怎么没有返回值?下面的说添加数据,我更不知所云了,但好像知道问题出在哪里了:

bestFeatLabel=labels[bestFeat]我的这句里面肯定是空的

果然还是有问题,但是pycharm为什么能运行啊???兼容性这么强?

黄天不负有心人啊!终于还是让我找到了答案

当我看到这个的时候,我想我知道问题在哪了

前面有一行代码这特么直接把原数据删了,我后面递归去哪里找数据去,果然是大坑啊!!!

解决办法:先复制一遍,然后再删掉

问题得到解决

之后在网上页看到了同样的说法

参考https://blog.csdn.net/coolerzz/article/details/79075539

一个晚上加一个上午终于把这个问题解决了!虽然很累,但是解决的那一刻还是很快乐的,哈哈哈哈哈哈

附上原码:

from math import log

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
    #currentLabel作为键,labelCounts[currentLabel]表示键对应的值,对于下面的简单数据集,labelcounts最终的结果是{'yes':2,'no':3}
    #适用所有类标签的发生频率计算类别出现的概率,利用这个概率计算香农熵
    shannonEnt=0.0
    for key in labelCounts:
        prob=float(labelCounts[key])/numEntries
        shannonEnt-=prob*log(prob,2)
    return shannonEnt
def creatDataSet():
    dataSet=[[1,1,'yes'],
             [1,1,'yes'],
             [1,0,'no'],
             [0,1,'no'],
             [0,1,'no']]
    labels=['no surfacing','flippers']
    return dataSet, labels
dataSet,labels=creatDataSet()
def splitDataSet(dataSet,axis,value):
    retDataSet=[]
    for featVec in dataSet:
        if featVec[axis]==value:
            reducedFeatVec=featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet
def chooseBestFeatureToSplit(dataSet):
    numFeatures=len(dataSet[0])-1
    #计算原始数据集信息熵,以便与划分后的数据集进行比较
    baseEntropy=calcShannonEnt(dataSet)
    #假设信息熵差值初值为0,最好的划分特征为最后一列
    bestInfoGain=0.0;bestFeature=-1
    for i in range(numFeatures):#循环特征
        featList=[example[i] for example in dataSet]
        #set()用于删除重复元素
        uniqueVals=set(featList)
        #uniqueVals得到了每一种(i)特征中的取值如(0,1)或者(yes,no)
        newEntropy=0.0
        #新的分类方式的信息熵
        for value in uniqueVals:#遍历第i个特征的取值
            #按照一种特征进行数据集划分,并计算当下的信息熵
            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
def majorityCnt(classList):#输入为分类名称的列表
    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):
    #取出dataset中的所有类标签,对于原数据集就是['yes', 'yes', 'no', 'no', 'no'],实际上是对于每个分支而言。
    classList=[example[-1] for example in dataSet]
    #如果该分支下全是相同的类别,即都是yes或者都是no,就返回这种分类(类别)
    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:{}}
    subLabels = labels[:]#大坑!!!!!!
    del(subLabels[bestFeat])#不复制就删会改变原来的数据
    featValues=[example[bestFeat] for example in dataSet]
    uniqueVals=set(featValues)
    for value in uniqueVals:#遍历当前选择特征的所有属性值
        #复制类标签,并将其存储在新列表变量sublabels中   
        subLabels=labels[:]
        #递归调用
        myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
    return myTree

 然而今天进行到后面画图又碰一鼻子灰

昨天调试的时候没有注意到结果,改了的代码,然而结果是错的:

{'no surfacing': {0: 'no', 1: {'no surfacing': {0: 'no', 1: 'yes'}}}}

而正确结果是:

{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

感觉昨天是高兴过了头,结果都疏忽掉了,然后今天发现之后继续回去分析昨天的代码,

    subLabels = labels[:]#大坑!!!!!
    del(subLabels[bestFeat])#不复制就删会改变原来的数据

突然就发现这个东西有问题了,这样做了之后这个labels根本就不更新了,每次都是一样的值,从而导致错误的结果!

然后我去想原本的代码:

del(labels[bestFeat])

还是和原来的想法,昨天是报超限问题,这个labels是有问题的,但是前面的代码都没有问题,还是想到的是bestFeat的问题,于是我把bestFeat打印出来看看到底超到哪里去了,结果打印出来bestFeat的值都是0,这是对的啊!!怎么会超限呢??

还是不甘心,我把代码重新组织了一下,又跑了一次,what the fuck!!!!!!!!!!居然跑出来了,没有报错 

顿时感觉,自己被这个jupyter notebook耍的团团转!!!!顿时心态爆炸!有木有。。

但是还好,问题解决了!兜兜转转又回到原点!!

猜你喜欢

转载自blog.csdn.net/Fengyutianqing/article/details/82178001