一、决策树算法的主要思想
它主要就是构建一个决策树表,通过数据集训练,递归选择最优特征,构成一个决策树。然后再通过这个决策树判断给定实例。
1 # -*- coding: UTF-8 -*- 2 from math import log 3 import operator 4 5 """ 6 函数说明:计算给定数据集的经验熵(香农熵) 7 8 Parameters: 9 dataSet - 数据集 10 Returns: 11 shannonEnt - 经验熵(香农熵) 12 Author: 13 Jack Cui 14 Blog: 15 http://blog.csdn.net/c406495762 16 Modify: 17 2017-07-24 18 """ 19 def calcShannonEnt(dataSet): 20 numEntires = len(dataSet) #返回数据集的行数 21 labelCounts = {} #保存每个标签(Label)出现次数的字典 22 for featVec in dataSet: #对每组特征向量进行统计 23 currentLabel = featVec[-1] #提取标签(Label)信息 24 if currentLabel not in labelCounts.keys(): #如果标签(Label)没有放入统计次数的字典,添加进去 25 labelCounts[currentLabel] = 0 26 labelCounts[currentLabel] += 1 #Label计数 27 shannonEnt = 0.0 #经验熵(香农熵) 28 # print(labelCounts) 29 for key in labelCounts: #计算香农熵 30 prob = float(labelCounts[key]) / numEntires #选择该标签(Label)的概率 31 shannonEnt -= prob * log(prob, 2) #利用公式计算 32 return shannonEnt #返回经验熵(香农熵) 33 34 """ 35 函数说明:创建测试数据集 36 37 Parameters: 38 无 39 Returns: 40 dataSet - 数据集 41 labels - 特征标签 42 Author: 43 Jack Cui 44 Blog: 45 http://blog.csdn.net/c406495762 46 Modify: 47 2017-07-20 48 """ 49 def createDataSet(): 50 dataSet = [[0, 0, 0, 0, 'no'], #数据集 51 [0, 0, 0, 1, 'no'], 52 [0, 1, 0, 1, 'yes'], 53 [0, 1, 1, 0, 'yes'], 54 [0, 0, 0, 0, 'no'], 55 [1, 0, 0, 0, 'no'], 56 [1, 0, 0, 1, 'no'], 57 [1, 1, 1, 1, 'yes'], 58 [1, 0, 1, 2, 'yes'], 59 [1, 0, 1, 2, 'yes'], 60 [2, 0, 1, 2, 'yes'], 61 [2, 0, 1, 1, 'yes'], 62 [2, 1, 0, 1, 'yes'], 63 [2, 1, 0, 2, 'yes'], 64 [2, 0, 0, 0, 'no']] 65 labels = ['年龄', '有工作', '有自己的房子', '信贷情况'] #特征标签 66 return dataSet, labels #返回数据集和分类属性 67 68 """ 69 函数说明:按照给定特征划分数据集 70 71 Parameters: 72 dataSet - 待划分的数据集 73 axis - 划分数据集的特征 74 value - 需要返回的特征的值 75 Returns: 76 无 77 Author: 78 Jack Cui 79 Blog: 80 http://blog.csdn.net/c406495762 81 Modify: 82 2017-07-24 83 """ 84 def splitDataSet(dataSet, axis, value): 85 retDataSet = [] #创建返回的数据集列表 86 for featVec in dataSet: #遍历数据集 87 if featVec[axis] == value: 88 reducedFeatVec = featVec[:axis] #去掉axis特征 89 reducedFeatVec.extend(featVec[axis+1:]) #将符合条件的添加到返回的数据集 90 retDataSet.append(reducedFeatVec) 91 return retDataSet #返回划分后的数据集 92 93 """ 94 函数说明:选择最优特征 95 96 Parameters: 97 dataSet - 数据集 98 Returns: 99 bestFeature - 信息增益最大的(最优)特征的索引值 100 Author: 101 Jack Cui 102 Blog: 103 http://blog.csdn.net/c406495762 104 Modify: 105 2017-07-20 106 """ 107 def chooseBestFeatureToSplit(dataSet): 108 numFeatures = len(dataSet[0]) - 1 #特征数量 109 baseEntropy = calcShannonEnt(dataSet) #计算数据集的香农熵 110 bestInfoGain = 0.0 #信息增益 111 bestFeature = -1 #最优特征的索引值 112 for i in range(numFeatures): #遍历所有特征 113 #获取dataSet的第i个所有特征 114 featList = [example[i] for example in dataSet] 115 uniqueVals = set(featList) #创建set集合{},元素不可重复 116 newEntropy = 0.0 #经验条件熵 117 for value in uniqueVals: #计算信息增益 118 subDataSet = splitDataSet(dataSet, i, value) #subDataSet划分后的子集 119 prob = len(subDataSet) / float(len(dataSet)) #计算子集的概率 120 newEntropy += prob * calcShannonEnt(subDataSet) #根据公式计算经验条件熵 121 infoGain = baseEntropy - newEntropy #信息增益 122 # print("第%d个特征的增益为%.3f" % (i, infoGain)) #打印每个特征的信息增益 123 if (infoGain > bestInfoGain): #计算信息增益 124 bestInfoGain = infoGain #更新信息增益,找到最大的信息增益 125 bestFeature = i #记录信息增益最大的特征的索引值 126 return bestFeature #返回信息增益最大的特征的索引值 127 128 129 """ 130 函数说明:统计classList中出现此处最多的元素(类标签) 131 132 Parameters: 133 classList - 类标签列表 134 Returns: 135 sortedClassCount[0][0] - 出现此处最多的元素(类标签) 136 Author: 137 Jack Cui 138 Blog: 139 http://blog.csdn.net/c406495762 140 Modify: 141 2017-07-24 142 """ 143 def majorityCnt(classList): 144 classCount = {} 145 for vote in classList: #统计classList中每个元素出现的次数 146 if vote not in classCount.keys():classCount[vote] = 0 147 classCount[vote] += 1 148 sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True) #根据字典的值降序排序 149 print(sortedClassCount) 150 return sortedClassCount[0][0] #返回classList中出现次数最多的元素 151 152 """ 153 函数说明:创建决策树 154 155 Parameters: 156 dataSet - 训练数据集 157 labels - 分类属性标签 158 featLabels - 存储选择的最优特征标签 159 Returns: 160 myTree - 决策树 161 Author: 162 Jack Cui 163 Blog: 164 http://blog.csdn.net/c406495762 165 Modify: 166 2017-07-25 167 """ 168 def createTree(dataSet, labels, featLabels): 169 classList = [example[-1] for example in dataSet] #取分类标签(是否放贷:yes or no) 170 if classList.count(classList[0]) == len(classList): #如果类别完全相同则停止继续划分 171 return classList[0] 172 if len(dataSet[0]) == 1: #遍历完所有特征时返回出现次数最多的类标签 173 return majorityCnt(classList) 174 bestFeat = chooseBestFeatureToSplit(dataSet) #选择最优特征 175 bestFeatLabel = labels[bestFeat] #最优特征的标签 176 featLabels.append(bestFeatLabel) 177 myTree = {bestFeatLabel:{}} #根据最优特征的标签生成树 178 del(labels[bestFeat]) #删除已经使用特征标签 179 featValues = [example[bestFeat] for example in dataSet] #得到训练集中所有最优特征的属性值 180 uniqueVals = set(featValues) #去掉重复的属性值 181 for value in uniqueVals: #遍历特征,创建决策树。 182 myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), labels, featLabels) 183 return myTree 184 185 """ 186 函数说明:使用决策树分类 187 188 Parameters: 189 inputTree - 已经生成的决策树 190 featLabels - 存储选择的最优特征标签 191 testVec - 测试数据列表,顺序对应最优特征标签 192 Returns: 193 classLabel - 分类结果 194 Author: 195 Jack Cui 196 Blog: 197 http://blog.csdn.net/c406495762 198 Modify: 199 2017-07-25 200 """ 201 def classify(inputTree, featLabels, testVec): 202 firstStr = next(iter(inputTree)) #获取决策树结点 203 secondDict = inputTree[firstStr] #下一个字典 204 featIndex = featLabels.index(firstStr) 205 for key in secondDict.keys(): 206 if testVec[featIndex] == key: 207 if type(secondDict[key]).__name__ == 'dict': 208 classLabel = classify(secondDict[key], featLabels, testVec) 209 else: classLabel = secondDict[key] 210 return classLabel 211 212 if __name__ == '__main__': 213 dataSet, labels = createDataSet() 214 featLabels = [] 215 myTree = createTree(dataSet, labels, featLabels) 216 print(myTree) 217 print(featLabels) 218 testVec = [0,1,1,1] #测试数据 219 result = classify(myTree, featLabels, testVec) 220 if result == 'yes': 221 print('放贷') 222 if result == 'no': 223 print('不放贷')
二、读代码收获
python的数组分割表达:(前:和后:还有::)
举例说明:a=[1,2,3,4,5,6]
a[-1]表示a数组中最后一个元素:6
a[1:]表示a数组从第2个元素开始到最后一个元素:[2,3,4,5,6]
a[:2]表示a数据从第一个元素开始到第二个元素:[1,2]
a[:-1]表示a数组从第一个元素到最后一个元素:[1,2,3,4,5,6]
a[::-1]表示将a数组反过来:[6,5,4,3,2,1]
a[::2]表示将a数组以步长为2输出:[1, 3, 5]