python决策树 math库ID3算法

每周一搏,提升自我。

python开发人工智能如火如荼,公司又安排任务,抱着无知者无畏的态度,开始学。

搭建环境:

    python:2.7.14

    编辑器:sublime text3

安装步骤和方法:https://my.oschina.net/wangzonghui/blog/1603104

安装学习库:

    pip install numpy

    pip install scipy

    pip install matplotlib

    pip install scikit-learn

决策树是人工智能的入门级监督式算法,从程序角度相对好理解,主要过程是根据训练数据的特征和结果,生成一套相应算法,评定测试数据,生成结论。

决策树的数学理论支持有香农熵(信息熵)基尼不纯度,本人对高等数学不怎么感冒,不是太懂,感兴趣的可以百度。

主流算法如下:

ID3:第一代,有缺陷,基础的一代,入门最好。选择最大增益的特征划分数据。

C45:ID3的扩展板增加了IDC功能。选择最大增益比的特征划分数据。

C50:C45的优化版,准确效率更高。是一个商业软件,公众是不可能得到的。

CART:分类回归树,使用基尼不纯度来决定划分,它和C45区别是 1、叶节点不是具体分类,而是一个函数,该函数定义了在该条件下的回归函数 2、CART是二叉树,不是多叉树。

除了CART其他都是基于香农熵实现。

下面是ID3代码:

#!/usr/bin/python
#coding:utf-8

from math import log
import operator

#计算给定数据集的香农熵
def calcShannonEnt(dataSet):
    numEntries=len(dataSet)  #数据集长度
    lableCounts={}
    for featVec in dataSet:
        currentLable=featVec[-1]  #数据集最后一个标签,特征数量-1
        if currentLable not in lableCounts.keys():
            lableCounts[currentLable]=0
        lableCounts[currentLable]+=1 #判断标签是否在当前字典的键值中,是键值为1
    shannonEnt=0
    for key in lableCounts:
        prob=float(lableCounts[key])/numEntries  #计算响应标签概率
        shannonEnt -=prob* log(prob,2)            #计算香农熵并且返回
    return shannonEnt

#创建简单的数据集   武器类型(0 步枪 1机枪),子弹(0 少 1多),血量(0 少,1多)  fight战斗 1逃跑 
def createDataSet():
    dataSet =[[1,1,0,'fight'],[1,0,1,'fight'],[1,0,1,'fight'],[1,0,1,'fight'],[0,0,1,'run'],[0,1,0,'fight'],[0,1,1,'run']]
    lables=['weapon','bullet','blood']
    return dataSet,lables

#按行打印数据集
def printData(myData):
    for item in myData:
        print '%s' %(item)

#给定特征划分数据集  dataSet(数据)  axis(数据下标)  value(数据值)
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

#选择最好的数据集划分方式 
#用这个方法必须满足条件:1、数据必须是一种由列元素组成的列表   2、所有列表元素都要具有相同的数据长度 
#3、数据的最后一列是当前数据的类别标签
def chooseBestFeatureToSplit(dataSet):
    numFeatures=len(dataSet[0])-1  #数据集最后一个标签,特征数量-1
    baseEntropy=calcShannonEnt(dataSet)
    bestInfoGain=0
    bestFeature=-1
    for i in range(numFeatures):
        featList=[example[i] for example in dataSet]
        uniqueVals =set(featList)
        newEntropy=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


#构建决策树
def createTree(dataSet,lables):
    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)
    bestFeat = chooseBestFeatureToSplit(dataSet)
    bestFeatLable = lables[bestFeat]
    myTree={bestFeatLable:{}}
    del(lables[bestFeat])
    featValues=[example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)
    for value in uniqueVals:
        subLables = lables[:]
        myTree[bestFeatLable][value] = createTree(splitDataSet(dataSet,bestFeat,value),subLables)
    return myTree


#挑选出现次数最多的分类名称
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 classify(inputTree,featLabels,testVec):
    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

#存储决策树
def storeTree(inputTree,filename):
    import pickle
    fw=open(filename,'w')
    pickle.dump(inputTree,fw)
    fw.close()


#获取决策树
def grabTree(filename):
    import pickle
    fr=open(filename)
    return pickle.load(fr)


######################运行测试######################
myDat,lables=createDataSet()
# printData(myDat)    #打印数据
#result=calcShannonEnt(myDat) #计算香农熵值
#print(result)

#根据传入特征拆分数据
# jiqiang=splitDataSet(myDat,0,1)
# printData(jiqiang)
# buqiang=splitDataSet(myDat,0,0)
# printData(buqiang)

# 比较所有特征的信息增益,返回最好特征划分的索引值
#chooseBestFeatureToSplit(myDat) #根据结果显示 武器类型值最大,是最好的用于划分数据集的特征

#构建决策树  {'weapon': {0: {'blood': {0: 'fight', 1: 'run'}}, 1: 'fight'}}
#该例子中包含了3个叶子节点和2个判断节点
tree=createTree(myDat,lables)
print(tree)

#根据决策树,预测结果
# dat,lab=createDataSet()
# result=classify(tree,lab,[1,0,0])
# print "结果是",result

直接运行出结果。天天学习,快乐无限。

猜你喜欢

转载自my.oschina.net/wangzonghui/blog/1615525
今日推荐