决策树算法详解(内附Python函数)

来源:互联网 发布:青岛易亚网络骗局 编辑:程序博客网 时间:2024/05/16 19:17

决策树算法(ID3):

数据集举例:(根据天气状况判断是否适合玩高尔夫球)


四个独立变量分别是(天气,温度,湿度,是否有风)

分类结果是 是否玩高尔夫球(PLAY)

算法步骤:

1.    计算整个数据集的熵。

以数据集最后一列分类结果作为数据依据(即PLAY那一列)

共14条记录,5条为不玩,9条为玩。

那么总的信息熵为

H(X)=0.409+0.530=0.939

2.    分别计算每个独立变量的熵

H(outlook)=5/14 (- 3/5 〖log〗_2  3/5-2/5 〖log〗_2  2/5)+4/14 (- 4/4 〖log〗_2  4/4-0/4 〖log〗_2  0/4)+
5/14 (- 3/5 〖log〗_2  3/5-2/5 〖log〗_2  2/5)

=0.693


由于温度是连续变量,我们要将其离散化,

Temper<70、70<=Temper<80、Temper>=80

H(temper)=  4/14 (- 3/4 〖log〗_2  3/4-1/4 〖log〗_2  1/4)+6/14 (- 4/6 〖log〗_2  4/6-2/6 〖log〗_2  2/6)+
4/14 (- 1/2 〖log〗_2  1/2-1/2 〖log〗_2  1/2)

=0.249+0.286+0.415=0.95

   

 同理,将湿度也离散化后计算其信息熵,

    Hum<80 、 80<=Hum<90、Hum>=90

 

H(hum)=6/14 (- 5/6 〖log〗_2  5/6-1/6 〖log〗_2  1/6)+4/14 (- 1/2 〖log〗_2  1/2-1/2 〖log〗_2  1/2)+
4/14 (- 1/2 〖log〗_2  1/2-1/2 〖log〗_2  1/2)

=0.278+0.415+0.415=1.108

H(wind)=6/14 (- 1/2 〖log〗_2  1/2-1/2 〖log〗_2  1/2)+8/14 (- 6/8 〖log〗_2  6/8-2/8 〖log〗_2  2/8)=0.428+0.498=0.926


3.  算出各自的信息增益,挑选最合适的特征值做为第一个父节点。

  Gain(outlook)= 0.939-0.693=0.246

  Gain(temper)= 0.939-0.95=-0.011

 Gain(hum)=0.939-1.108=-0.169

 Gain(wind)=0.939-0.926=-0.013

可以得出做为父节点的为 outlook.

4.   根据上面计算结果,可以做第一次数据集的划分:



5.    分别对sunny 和rain下面的表格进行划分,方法同前三步。分别计算总的信息熵和各类属性特征的信息熵,选出最好的信息增益,做为 下一个分割点。

Sunny:

H=-  3/5 〖log〗_2  3/5-2/5 〖log〗_2  2/5=0.970

H(temper)=  2/5 (- 1/2 〖log〗_2  1/2-1/2 〖log〗_2  1/2)=0.4

Gain(temper)=0.57

H(hum)=0 

Gain(hum)=0.97

H(wind)=  2/5 (- 1/2 〖log〗_2  1/2-1/2 〖log〗_2  1/2)+3/5 (- 2/3 〖log〗_2  2/3-1/3 〖log〗_2  1/3)=0.4+0.4=0.8 

 

Gain(wind)=0.17

分割点为(Temper)


Rain:

H=-  3/5 〖log〗_2  3/5-2/5 〖log〗_2  2/5=0.970

 

H(temper)=  =  2/5 (- 1/2 〖log〗_2  1/2-1/2 〖log〗_2  1/2)+3/5 (- 2/3 〖log〗_2  2/3-1/3 〖log〗_2  1/3)=0.8

Gain(temper)=0.17

 

H(hum)= 3/5 (- 2/3 〖log〗_2  2/3-1/3 〖log〗_2  1/3)=0.4

Gain(hum)=0.57

 

H(wind)=0

Gain(wind)=0.97

分割点为(Wind)

6.     根据第二次信息增益计算,可划分第二次数据集:



7.根据第二步分解,只剩余一个节点不纯,我们继续按照之前的方法分类。最终结果为:



8.     算法实现

用Python实现决策树算法需要编写的函数:

1>  计算信息熵

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:        prop = float(labelCounts[key])/numEntries        shannonEnt -= prop*log(prop, 2)    return  shannonEnt

2>  根据特征值划分数据集

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

3>  计算信息增益挑选最大特征值

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

4>  递归算法构造决策树

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