#决策树
#环境:Linux、python3.7.5 ''' 决策树的一个重要任务是为了了解数据结构中所蕴含的知识信息,因此决策树可以使用不熟悉的数据集合,并从中提取出一系列规则, 这些机器根据数据集创建规则的过程,就是机器学习的过程。专家系统中经常使用决策树,而且决策树给出结果往往可以匹敌在当前 领域具有几十年工作经验的人类专家。 优点: 计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。 缺点:可能产生过度匹配问题。 适用数据类型:数值型和标称型。 讨论如何用python代码来构建决策树 1.在构造决策树时,我们需要解决的第一个问题是,当前数据集上哪个特征在划分数据分类时起决定性作用。 决策树的一般流程: 1.收集数据:可以使用任何方法 2.准备数据:树构造算法只适用于标称型数据,因此数值型数据必须离散化 3.分析数据:可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期 4.训练算法:构造树的数据结构 5.测试算法:使用经验树计算错误率 6.使用算法:此步骤可以适用于任何监督学习算法,而使用决策树可以更好的理解数据的内在含义 ''' ''' 信息增益计算方法: 划分数据集的大原则:将无序的数据变得更加有序。 组织杂乱无章数据的一种方法就是使用信息论度量信息 ''' import operator #计算信息熵,用来划分数据集 from math import log 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 * log(prob,2) return shannonEnt def createDataSet(): dataSet = [ [1,1,'yes'], [1,1,'yes'], [1,0,'no'], [0,1,'no'], [0,1,'no'] ] labels = ['no surfacing', 'flippers'] #只是标签,“不浮出水面是否可以生存”、“是否有脚蹼” yes和no为是否属于鱼类 return dataSet, labels #按照给定特征划分数据集 def splitDataSet(dataSet, axis, value): retDataSet = [] for featVec in dataSet: if featVec[axis] == value: reduceFeatVec = featVec[:axis] reduceFeatVec.extend(featVec[axis+1:]) retDataSet.append(reduceFeatVec) 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) #数据集中所有第i列不重复的特征 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 ''' 递归构建决策树 目前我们已经学习了从数据集构造决策树算法所需的子功能模块,其工作原理如下: 得到原始数据集,然后基于最好的属性值(chooseBestFeatureToSplit)划分数据集, 由于特征值可能多于两个,因此可能存在大于两个分支的数据集划分(多分类)。第一次划分之后, 数据将被向下传递到树分支的下一个节点,在这个节点上,我们可以再次划分数据。因此我们可以采用 递归的原则处理数据集。 递归结束的条件是:程序遍历完所有划分数据集的属性,或者每个分支下所有实例都具有相同的分类。 ''' #返回出现次数最多的分类名称 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.iteritems(1), reverse=True) return sortedClassCount[0][0] #创建树的函数代码 #dataSet数据集 labels标签列表 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 def retrieveTree(i): listOfTrees = [{'no surfacing':{0:'no', 1:{'flippers': \ {0:'no', 1:'yes'}}}}, {'no surfacing':{0:'no', 1:{'flippers': \ {0:{'head':{0:'no', 1:'yes'}}, 1:'no'}}}} ] return listOfTrees[i] #绘制树形图 接口 #暂无 #隐形眼镜决策树模型示例 #暂无
#测试和存储分类器 ''' 下面我们把重点转移到如何利用决策树执行数据分类上。 我们将使用决策树构建分类器,并介绍实际应用中如何存储分类器。之后我们将在真实数据上使用决策树分类算法, 验证它是否可以正确预测出患者应该使用的隐形眼镜类型。 ''' def classify(inputTree, featLabels, testVec): firstStr = list(inputTree.keys())[0] secondDict = inputTree[firstStr] featIndex = featLabels.index(firstStr) for key in secondDict.keys(): if testVec[featIndex] == key: if type(secondDict[key]).__name__=='dict': classLabel = classify(secondDict[key], featLabels, testVec) else: classLabel = secondDict[key] return classLabel #决策树的存储,使用pickle模块存储决策树 def storeTree(inputTree, filename): import pickle fw = open(filename, 'wb') pickle.dump(inputTree, fw) fw.close() #加载 决策树 def grabTree(filename): import pickle fr = open(filename,'rb') return pickle.load(fr) if __name__ == '__main__': ''' #决策树接口测试 myDat,labels=createDataSet() #calcShannonEnt(myDat) #splitDataSet(myDat,0,1) #print('最好数据集划分特征特为第:',chooseBestFeatureToSplit(myDat), '列。') ''' ''' #构建决策树 myDat,labels=createDataSet() myTree=createTree(myDat, labels) print(myTree) ''' ''' #存储和加载树 myDat,labels=createDataSet() myTree=createTree(myDat, labels) storeTree(myTree, 'classifierStorage.txt') ret = grabTree('classifierStorage.txt') print(ret) ''' #测试决策树分类效果 myDat,labels=createDataSet() myTree=grabTree('classifierStorage.txt') ret=classify(myTree, labels, [1,1]) print(ret)