机器学习笔记:ID3算法建立决策树(二)

来源:互联网 发布:iphone笔记软件 编辑:程序博客网 时间:2024/05/20 05:58

在《机器学习笔记:ID3算法建立决策树(一)》中记录了ID3算法的计算公式和步骤,现在用例子记录一下ID3构建决策树的过程。
对以下数据进行分类:

- 是否能飞? 是否有羽毛? 是小鸟? 1 是 是 是 2 是 是 是 3 是 否 否 4 否 是 否 5 是 否 是

是否能飞用0,1表示,0不能飞,1能飞;
是否有羽毛用0,1表示,0没有羽毛,1有羽毛;
也就是用是否能飞,是否有羽毛去判断一个东西是不是小鸟
用矩阵表达如下:

def createDataSet():    dataSet = [[1,1,'是'],               [1,1,'是'],               [1,0,'否'],               [0,1,'否'],               [0,1,'否']]    labels = ['能飞的','有羽毛的']    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 * math.log(prob,2)    return shannonEnt

对整个样本数据按类别划分子集:

def splitDataSet(dataSet,axis,value):    retDataSet = []    for featVec in dataSet:        if featVec[axis] == value:            #featVec 是一维数组,下标为axis元素之前的值加入到reducedFeatVec            reducedFeatVec = featVec[:axis]                #下一行的内容axis+1之后的元素加入到reducedFeatVec            reducedFeatVec.extend(featVec[axis+1:])               retDataSet.append(reducedFeatVec)    return retDataSet   

选择信息增益最大的维度(列,也可以理解为属性)作为决策树的根节点

def chooseBestFeatureToSplit(dataSet):    numFeatures = len(dataSet[0]) - 1               baseEntropy = calcShannonEnt(dataSet)            bestInfoGain = 0.0    bestFeature = -1    for i in range(numFeatures):        featList = [example[i] for example in dataSet]        uniqueVals = set(featList)  #值去重        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           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):    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:{}}    del(labels[bestFeat])    featValues = [example[bestFeat] for example in dataSet]    uniqueVals = set(featValues)    for value in uniqueVals:        subLabels = labels[:]        #对每个特征集递归调用建树方法        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)    return myTree

调用

myDat,labels = createDataSet()print(createTree(myDat, labels))

结果

{'能飞的': {0: '否', 1: {'有羽毛的': {0: '否', 1: '是'}}}}

接下来继续学习图形化显示决策树,更直观。

总结

计算各属性的信息增益,找出最大者为根节点
先验熵:样板数据中,先求出各种值出现的概率P(ui),再利用公式求熵
后验熵:对其他列,先求出各种值出现的概率P(vi),再求出先验列中各种值对本列取值为vi时的概率P(u|vi),再根据公式求熵H(U|vi),把u为各种值的情况下的H(U|vi) 算出来
条件熵:对后验熵在输出符号集V中求期望,接收到全部符号后对信源的不确定性,根据后验熵得到的P(vi)乘以H(U|vi)之和
信息增益:先验熵与条件熵的差,即先验熵中求得的P(ui)减去条件熵
拆分子集:对作为根节点的属性的数据根据不同的值分成子集。
对剩余属性重复上述步骤。

这是个人理解,如果有不到位的地方,或者有理解偏差,希望有人能指出扶正,交流学习。

0 0
原创粉丝点击