机器学习——决策树算法
来源:互联网 发布:室内设计学习软件 编辑:程序博客网 时间:2024/06/05 01:23
决策树的主要任务就是探寻数据中所蕴含的知识信息。所以决策树可以使用不熟悉的数据集,并从中提取出一系列规则,而这些规则的提炼过程就是机器学习的过程。
在构造决策树时必须要面对的问题是:当前我们究竟该选哪个特征来进行数据的分类。为了找到决定性的特征,划分出最好的结果,我们必须评估每个特征。
完成测试之后,原始数据集就被划分为几个数据子集。这些数据子集会分布在第一个决策点的所有分支上。如果分支下的数据属于同一类型,则当前的数据集无需进一步划分;如果数据子集内的数据不属于同一类型,则需要重复划分数据子集的过程。如何划分数据子集的方法和划分原始数据集的方法相同,直到所有具有相同类型的数据均在一个数据子集内。上面介绍的就是ID3算法,我们在每次划分数据集的时候都只选取一个特征属性。
划分数据的根本原则就是:将无序的数据变的更加有序。划分前后信息发生的变化我们称之为信息增益,知道如何计算信息增益,我们就可以计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。
那么如何计算那个虚无缥缈的信息增益呢?针对这个问题香农同学提出了一个:熵的概念。在高中物理也提到过熵,它标识物体的无序程度。而我们这里使用的熵则代表了信息的无序程度。熵定义为信息的期望值,符号的信息定义为:
------- 1
其中是选择该分类的概率。
为了计算熵,我们需要计算所有分类可能包含的信息期望值,可以通过如下的公式得到:
------- 2
其中n是分类的数目。
下面给出计算信息熵的Python代码:
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:#通过前面的公式2计算信息熵 prob = float(labelCounts[key])/numEntries#分类出现概率 shannonEnt -= prob * log(prob,2) #log base 2return shannonEnt
其中,返回的熵越大,说明数据的无序程度越高。
在具体进行数据集划分的时候,我们将对每个特征划分数据集的结果计算一次信息熵,然后判断按照哪个特征划分数据集是最好的选择。
在划分具体数据集时,可以使用如下的代码实现:
#三个参数为:待划分的数据集,划分数据集的特征索引,需要返回的特征值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
接下来我们将利用香农熵和前面的splitDataSet函数帮我们找到最好的特征划分方式。具体代码如下:
def chooseBestFeatureToSplit(dataSet): numFeatures = len(dataSet[0]) - 1 #计算特征的数量 baseEntropy = calcShannonEnt(dataSet)#计算最初的熵值 bestInfoGain = 0.0; bestFeature = -1for 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 = ireturn 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
以上就是递归实现决策树创建的代码。在对“树”这个数据结构进行编程的时候,我们常常会看到递归实现,因为“树”本身就是以递归的方式进行定义的,所以在构建的时候使用递归的方式,思路也会更清晰。
到这里我们已经完成了决策树的具体构建,下面就是对它进行使用的部分了,实现的代码如下:
#输入参数依次为:构建好的决策树,特征列表,测试向量def classify(inputTree,featLabels,testVec): #取得第一个键值firstStr = inputTree.keys()[0]#取得根键值所对应的字典结构secondDict = inputTree[firstStr]#得到对应键值在属性列表中的索引featIndex = featLabels.index(firstStr)#取得测试向量中对应索引的值key = testVec[featIndex]#根据前面的值再次取到对应的取值结构valueOfFeat = secondDict[key]#如果该结构是字典,则需进一步分析 if isinstance(valueOfFeat, dict): classLabel = classify(valueOfFeat, featLabels, testVec) #若不是字典,则直接返回对应的值 else: classLabel = valueOfFeat return classLabel
例如我们可以如下来构造和使用决策树算法:
myDat, labels = createDataSet()wlabels = labels[:] #copy,因为createTree会改变传入参数的值myTree = createTree(myDat, wlabels)firstStr = myTree.keys()[0]print classify(myTree, labels, [1,0]) print classify(myTree, labels, [1,1])
执行效果如下:
其中createDataSet函数的定义如下:
def createDataSet(): dataSet = [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']] labels = ['no surfacing','flippers']return dataSet, labels
- 机器学习算法2——决策树
- 机器学习算法——决策树
- 机器学习——决策树算法
- 机器学习算法——决策树总结
- 机器学习——决策树算法
- Python机器学习算法——决策树
- 机器学习——决策树算法
- 机器学习算法—决策树应用
- 机器学习—CART决策树算法详解
- 机器学习—决策树
- 机器学习算法---决策树
- 机器学习算法-决策树
- 机器学习算法-决策树
- 机器学习--决策树算法
- 机器学习-算法--决策树
- 机器学习-决策树算法
- 机器学习:决策树算法
- 机器学习算法-决策树
- 史上最简单的 MySQL 教程(二十)「数据的高级操作 之 主键冲突」
- C语言--实现队列的入队出队
- 图的深度遍历
- (个人)AR电子书系统创新实训第四周(2)
- Selective Search for Object Recoginition
- 机器学习——决策树算法
- mysql 多表联合update
- ubuntu永久关闭ntp服务
- 数据库管理系统(DBMS)
- R语言线性回归之逐步回归
- 我与eclipse的第一次约会
- 剑指offer 面试题44 扑克牌的顺子
- 梯度下降和牛顿法
- (项目)AR电子书系统创新实训第四周(1)