决策树ID3算法的python实现

来源:互联网 发布:java泛型方法 编辑:程序博客网 时间:2024/05/22 16:33

决策树ID3算法的python实现

环境:win7 64位 python3.5

熵参考:http://blog.csdn.net/ggwcr/article/details/77964184

import numpy as npfrom math import logimport operatordef createDataSet():    dataSet = [        [1, 1, 'yes'],        [1, 1, 'yes'],        [1, 0, 'no'],        [0, 1, 'no'],        [0, 1, 'no']    ]    labels = ['no surfacing', 'flippers']    return dataSet, labels# 计算给定数据集的香浓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    shannonEnt = 0.0    for key in labelCounts:        prob = float(labelCounts[key])/numEntries # 使用频率代替概率        shannonEnt -= prob*log(prob, 2)    return shannonEnt# 按照给定特征划分数据集# 参数:待划分的数据集、划分数据集的特征、要抽取的特征的值def splitDataSet(dataSet, axis, value):    retDataSet = []         # 创建一个空的列表    for featVec in dataSet:        if featVec[axis] == value:            # 取划分特征值前面一部分,但不包括特征值            reduceFeatVec = featVec[:axis]             # 取划分特征值后面一部分,但不包括特征值            reduceFeatVec.extend(featVec[axis+1:])               """            以上两行获得的数据集将不包括特征值的记录,            以达到每一次划分都将大数据集划分为小数据集的目的            """            # 以每条记录为单位追加到空列表中            retDataSet.append(reduceFeatVec)                return retDataSet# featList = [example[i] for example in dataSet]'''array([[ 1,  1,  0,  4],       [ 0,  1,  1,  8],       [ 1,  0,  1, 12],       [ 1,  1,  1,  9],       [ 0,  0,  0,  7]])------------------------------for i in range(3):    featList = [example[i] for example in dataSet]    print 'example[i] : ', example[i]    print 'example : ', example    print featList-----------------------------    example[i] :  0    example :  [0 0 0 7]    featList : [1, 0, 1, 1, 0]    example[i] :  0    example :  [0 0 0 7]    featList : [1, 1, 0, 1, 0]    example[i] :  0    example :  [0 0 0 7]    featList : [0, 1, 1, 1, 0]'''# 循环计算香农熵和splitDataSet()函数,找到最好的特征划分方式def chooseBestFeatureToSplit(dataSet):    # 一行中的长度减去标称变量剩下的就是特征值的数量    numFeatures = len(dataSet[0]) -1     #计算了整个数据集的原始香农熵,保存最初的无序度量值,.用于与划分完之后的数据集计算的嫡值进行比较    baseEntropy = calcShannonEnt(dataSet)     bestInfoGain = 0.0    bestFeature = -1    # 循环遍历数据集中的所有特征    for i in range(numFeatures):             # featList是List可以包含重复的特征值        featList = [example[i] for example in dataSet] # 第i列的特征值的列表 如第0列[1, 1, 1, 0, 0]        # set中的每一个值都不相同        uniqueVals = set(featList)  # 第i列特征值的枚举类型 如第0列 {0, 1}        newEntropy = 0.0        # 遍历当前特征中的所有唯一属性值,对每个特征划分一次数据集        for value in uniqueVals:            # subDataSet为剃掉特征值i的子集#             print("===============================")#             print("value: ",value)            subDataSet = splitDataSet(dataSet, i, value) #             print("subDataSet: ",subDataSet)            # 第i列特征向量不同取值为value占总体样本的比例            prob = len(subDataSet)/float(len(dataSet))#             print("len(subDataSet): ",len(subDataSet))#             print("len(dataSet): ",len(dataSet))            newEntropy += prob * calcShannonEnt(subDataSet)          # 计算信息增益 信息增益是熵的减少或者是数据无序度的减少        infoGain = baseEntropy - newEntropy                             if (infoGain > bestInfoGain):            bestInfoGain = infoGain            bestFeature = i    return bestFeaturedef majorityCnt(classList):    classCount = {}    for vote in classList:        if vote not in classCount.keys():            classCount = 0        classCount[vote] += 1    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)    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)                           # 采用多数多数原则选出分组    bestFeat = chooseBestFeatureToSplit(dataSet)                # 选出最佳的特征值    bestFeatLabel = labels[bestFeat]                            # 获取该特征的名称    # 这里直接使用字典变量来存储树信息,这对于绘制树形图很重要。    myTree = {bestFeatLabel:{}}                                 # 当前数据集选取最好的特征存储在bestFeat中    del(labels[bestFeat])                                       # 删除已经在选取的特征    featValues = [example[bestFeat] for example in dataSet]    uniqueVlas = set(featValues)    for value in uniqueVlas:        subLabels = labels[:]                                   # 复制所有标签,这样树就不会破坏现有的标签        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)    return myTree
myDat,labels = createDataSet()print("myDat:",myDat)MyTree = createTree(myDat,labels)print(MyTree)
myDat: [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
原创粉丝点击