数据挖掘-经典算法-决策树ID3算法实现


from math import log
import operator

def calcShannonent(dataSet):                        #计算数据的熵(entropy)
    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
    for key in labelCounts:
        prob = float(labelCounts[key])/numEntries  #计算单个类的熵值
        shannonEnt -= prob*log(prob, 2)             #累加每个类的熵值
    return shannonEnt

def createDataSet_temp():
    #创造实例数据
    labels = ['头发', '声音']

    with open('TreeGrowth_ID3.txt', 'r', encoding='UTF-8') as f:		#改了一个文件读写
        dataSet = [[] for i in range(9)]
        value = ['长', '短', '粗', '细', '男', '女']
        num_line = 0
        for line in f:
            # re.split(r'(\s{8}\[\')|(\', \')|(\'\],)|(\'\])', line)			#尝试使用正则划分,失败了
            for i in line:
                if (i in value):
                    dataSet[num_line].append(i)
            num_line += 1
        del(dataSet[0])
    '''
    dataSet = [
        ['长', '粗', '男'],
        ['短', '粗', '男'],
        ['短', '粗', '男'],
        ['长', '细', '女'],
        ['短', '细', '女'],
        ['短', '粗', '女'],
        ['长', '粗', '女'],
        ['长', '粗', '女']
    ] 
    '''
    return dataSet, labels

def splitDataSet(dataSet, axis, value):             #按某个特征分类后的数据
    retDataSet = []
    for featVec in dataSet:
        if featVec[axis] == value:                  #axis表示指定属性在label中的标号,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)           #原始熵
    bestInfoGain = 0
    bestFeature = -1
    for i in range(numFeatures):                    #循环每一个特征
        featList = [example[i] for example in dataSet]#读取每一条记录取出其中第i个属性的值,并新建一个列表
        uniqueVals = set(featList)                  #set()创建一个无序不重复元素集,可进行关系测试,删除重复元素,进行交差并集运算
        newEntropy = 0
        for value in uniqueVals:                    #对于第i个属性值列表中每一个值
            subDataSet = splitDataSet(dataSet, i, value)    #subDataSet是去掉了第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):                         #多数表决排序,如:最后分类为2男1女则判断为男
    classCount = {}
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote] = 0
        classCount[vote] += 1
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    #将items返回的可遍历键值对数组,根据键值对的第二个域(值),进行降序排列
    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)    #找到最优特征的标号
    if(bestFeat == -1):                             #自己添加的,不然报错
        return classList[0]
    bestFeatLabel = labels[bestFeat]                #找到最优特征
    myTree = {bestFeatLabel:{}}                     #分类结果以字典形式保存,得到树的当前层
    del(labels[bestFeat])                           #删除labels中当前最优特征
    featValues = [example[bestFeat] for example in dataSet]#将记录集中当前最优特征的值形成列表
    uniqueVals = set(featValues)                    #对值集去重
    for value in uniqueVals:                        #对于每个值
        subLabels = labels[:]                       #subLabels为去除当前最优特征的特征集
        myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
        #使用递归,创造下一层树,~~~~~~~~~~~~~~~~~~~~~~
    return myTree

if __name__=='__main__':
    dataSet, labels = createDataSet_temp()          #创造示例数据
    print(createTree(dataSet, labels))              #输出决策树模型结果



代码来自:https://blog.csdn.net/csqazwsxedc/article/details/65697652
改了一点点
加了很多注释

你可能感兴趣的:(数据挖掘)