决策树C4.5了解一下[微笑]

决策树遵循“分而治之”策略,是一种树形结构,其中每个内部结点表示在一个属性上的测试,每个分支代表一个测试输出,每个叶结点代表一种类别,目的是产生一颗泛化能力强,即处理未见示例能力强的决策树。

优点:可以自学习

缺点:过拟合、泛化能力弱,生成的树不一定全局最优

划分选择:决策树学习的关键是如何划分属性,使得结点的“纯度”越来越高,具体的可按照三种划分标准。

1.信息增益(ID3决策树学习算法):表示得知特征A的信息而使得类X的信息的不确定性减少的程度。信息增益越大,意味着使用属性来进行划分所获得的纯度提升越大。

信息熵 = 经验熵H(D) – 经验条件熵(H(D|A))

2.增益率(C4.5决策树算法):信息增益可能对数目较多的属性有偏好,为减少这种偏好使用增益率。C4.5算法是先从划分属性中找出信息增益高于平均水平的属性,然后在选择增益率最高的。

3.基尼指数(CART决策树算法):Gini(D)反映了从数据集中随机抽取两个样本,其类别标记不一致的概率,Gini(D)越小,数据集D的纯度越高。在选择划分属性时,我们选择基尼指数最小的属性作为最优划分属性。

下面是未剪枝C4.5python实现的代码:

  1 import math
  2 import operator
  3 import xlrd
  4 #功能:导入数据表
  5 #功能:计算熵
  6 def calcShannonEnt (dataSet):
  7     num = len(dataSet)#实例的个数
  8     labelCounts = {}#类标签
  9     for featVec in dataSet:
 10         currentLabel = featVec[-1]#最后一列的数值
 11         if currentLabel not in labelCounts.keys():#如果在labelCounts中没出现
 12             labelCounts[currentLabel] = 0#就把currentLabel键加入labelCounts中,值为0
 13         labelCounts[currentLabel] += 1#labelCounts对应的值就加一
 14     #计算香农熵H(D)
 15     ShannonEnt = 0.0
 16     for key in labelCounts:
 17         prob = float(labelCounts[key]) / num#计算p(Xi)概率
 18         ShannonEnt -= prob * math.log(prob, 2) 
 19     return ShannonEnt
 20 
 21 #功能:按照给定特征划分数据集
 22 #输入:数据集、划分数据集的特征、需要返回的特征的值
 23 #返回:划分后的数据集
 24 def splitDataSet(dataSet, axis, value):
 25     newdataSet = []
 26     for featVec in dataSet:
 27         if featVec[axis] == value:
 28             reducedFeatVec = featVec[:axis]
 29             reducedFeatVec.extend(featVec[axis+1:])
 30             newdataSet.append(reducedFeatVec)
 31     return newdataSet
 32 
 33 #功能:选取最好的数据集划分方式
 34 #返回:最佳特征下标(增益率最大)
 35 def chooseBestFeatureTosplit(dataSet):
 36     numFeatures = len(dataSet[0]) - 1#特征个数
 37     baseEntropy = calcShannonEnt(dataSet)#原始香农熵H(D)
 38     bestInfoGainrate = 0.0; bestFeature = -1#信息增益和最好的特征
 39     #遍历特征
 40     for i in range(numFeatures):
 41         featureSet = set([example[i] for example in dataSet])#第i个特征取值集合
 42         newEntropy = 0.0
 43         splitinfo = 0.0
 44         for value in featureSet:
 45             subDataSet = splitDataSet(dataSet, i, value)
 46             prob = len(subDataSet)/float(len(dataSet))
 47             newEntropy += prob * calcShannonEnt(subDataSet)#经验条件熵H(D|A)
 48             splitinfo -= prob * math.log(prob,2)#经验熵HA(D)
 49         #当概率为1或者0时(因为经验熵要做被除数):
 50         if not splitinfo:
 51             splitinfo = -0.99 * math.log(0.99,2) - 0.01 * math.log(0.01,2)
 52         infoGain = baseEntropy - newEntropy#信息增益=H(D)-H(D|A)
 53         infoGainrate = float(infoGain) / float(splitinfo)#增益率=信息增益/经验熵
 54         if infoGainrate > bestInfoGainrate:
 55             bestInfoGainrate = infoGainrate
 56             bestFeature = i
 57     return bestFeature
 58 
 59 #功能:多数表决决定叶子结点
 60 #使用分类名称的列表,创建键值为classList中唯一值的数据字典,字典对象存储了classList每个类标签出现的频率
 61 #返回:出现次数最多的分类名称
 62 def majorityCnt(classList):
 63     classCount = {}
 64     for vote in classList:
 65         if vote not in classCount.keys(): 
 66             classCount[vote] = 0
 67         classCount[vote] += 1
 68     sortedClassCount = sorted(ClassCount.iteritems(),key = operator.itemgetter(1), reverse = True)
 69     return sortedClassCount[0][0]
 70 
 71 #功能:创建树
 72 #输入数据集和类标签
 73 #返回字典树
 74 def createTree(dataSet, labels):
 75     classList = [example[-1] for example in dataSet]#数据集的所有类标签
 76     if classList.count(classList[0]) == len(classList):#停止条件是所有的类标签完全相同
 77         return classList[0]
 78     if len(dataSet[0]) == 1:#当使用完了所有特征,还不能将数据集划分成仅包含唯一类别的分组
 79         return majorityCnt(classList)#挑选出出现次数最多的类别作为返回值
 80     #开始创建树
 81     bestFeat = chooseBestFeatureTosplit(dataSet)#当前数据集选取的最好特征
 82     bestFeatLabel = labels[bestFeat]
 83     myTree = {bestFeatLabel:{}}
 84     #得到列表包含的所有属性值
 85     #赋值当前特征标签列表,防止改变原始列表的内容
 86     subLabels = labels[:]
 87     #删除属性列表中当前分类数据集特征
 88     del(subLabels[bestFeat])
 89     #获取数据集中最优特征所在列
 90     featValues = [example[bestFeat] for example in dataSet]
 91     #采用set集合性质,获取特征的所有的唯一取值
 92     uniqueVals = set(featValues)
 93     for value in uniqueVals:
 94         myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)
 95     return myTree
 96 
 97 '''    功能:决策树分类函数
 98     思路:
 99     执行数据分类时,使用决策树以及用于构造决策树的标签向量。
100     比较测试数据与决策树上的数值
101     递归执行该过程直到进入叶子结点
102     将测试数据定义为叶子结点所属的类型
103 '''
104 def classify(inputTree, featLabels, testVec):
105     #将标签字符串转换为索引
106     firstSides = list(inputTree.keys())
107     firstStr = firstSides[0]
108     secondDict = inputTree[firstStr]
109     featIndex = featLabels.index(firstStr)
110     #-----------------------------------
111     for key in secondDict.keys():
112         if testVec[featIndex] == key:
113             if type(secondDict[key]).__name__ =='dict':
114                 classLabel = classify(secondDict[key], featLabels, testVec)
115             else:    classLabel = secondDict[key]
116     return classLabel
117 
118 #功能:后剪枝
119 def 
120 
121 #功能:观察决策树的分类率
122 def getAccuracy(dataSet,testDatas,testLabels,myTree):
123     count = 0#分类正确的数量
124     print('数据量:',len(testDatas))
125     print('属性数量:',len(testLabels))
126     num = 0#分类正确的数量
127     for testData in testDatas: 
128         i = 0
129         a = classify(myTree, testLabels,testData)
130         if a == dataSet[i][-1]:
131             count += 1
132         i += 1
133     print("分类正确的数量是: ",count)
134     accuracy = count / len(testDatas)
135     print("决策树分类器的正确率为:",accuracy)

 

posted @ 2018-05-09 13:52  抹茶奶绿不加冰  阅读(1598)  评论(0编辑  收藏  举报