国庆过完,继续干活~
下面总结了几个ensemble的模型的本质,顺便调出决策树的概念:
在不同的情形下,用不同的g的一种方式。
蓝色的部分是leaf,也就是base hypothesis。
内部决策的过程叫做node。通常是很简单的决定。
或者:
递回的概念,一棵树可以用其他的几棵树来代表。
决策树的优缺点:
优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关的特征数据。
缺点:可能会产生过度匹配的问题。
伪代码:
检测数据集中的每一个子项书否属于同一分类: if so return 类标签; else 寻找划分数据集的最好特征 划分数据集 创建分支节点 for 每个划分的子集 调用函数并增加返回结果到分支节点中 return 分支节点
决策树演算法的大概思路:
当然还需要考虑递回式的停止条件:
下面重点介绍CART演算法:
每次做判断只做二元的分类;
选择判断的条件是进过划分后的数据更加纯了。(y一或者y很接近)
那么纯度又如何进行计算呢?
把切开两块的综合的纯度进行考量,所谓综合就是进行加权。就是两边的不纯度的加权相加,进行最小化的优化。
下面是决策树停止的条件:
当分无可分的时候,就会被迫停下来,就叫fully grown tree。然而在这个时候,过拟合就不可避免的发生了。
所以我们需要剪枝这个动作来做一些正则化的事情。模型的复杂度的衡量可以用树叶的数量来进行。
剪掉不同的叶子的数量中做一个最好的选择。
当出现missing value的时候:
要么想办法补齐这个missing的值,要么使用其他的可替代的feature来进行切割。
总结:
代码:
#计算给定数据集的香农熵from math import logdef calShannonEnt(dataSet): numEntries = len(dataSet) #为所有可能的分类创建字典 labelCounts = {} for featVec in dataSet: #字典的键值是最后一列的数值 currentLabel = featVec[-1] #如果当前键值不存在,则拓展字典,将当前键值加入字典 if currentLabel not in labelCounts.keys(): lableCounts[currentLabel] = 0 #每个键值都记录了当前类别出现的次数 lableCounts[currentLabel] += 1 shannonEnt = 0.0 #最后,使用所有类标签的发生频率计算类别出现的概率,我们将用这个概率计算香农熵 for key in lableCounts: prob = float(lableCounts[key])/numEntries shannonEnt -= prob * log(prob,2) return 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#选择最好的数据集的划分方式def chooseBestFeatureToSplit(dataSet): numFeatures = len(dataSet[0]) - 1 baseEntropy = calShannonEnt(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 * calShannonEnt(subDataSet) infoGain = baseEntropy - newEntropy #比较所有特征中的信息增益,返回最好的特征划分的索引值 if (infoGain > bestInfoGain): bestInfoGain = infoGain bestFeature = i return bestFeature#创建树的函数代码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) bestFestLabel = labels[bestFeat] #开始创建树 myTree = {bestFestLabel:{}} del(labels[bestFeat]) featValues = [example[bestFest] for eample in dataSet] uniqueVals = set(featValues) for value in uniqueVals: subLabels = labels[:] myTree[bestFestLabel][value] = createTree(splitDataSet(dataSet,bestFeat,value),subLabels) return myTree