决策树
决策树
- 优点: 计算复杂度不高, 输出结果易于理解, 对中间值的缺失不敏感,可以处理不相关特征数据。
- 缺点: 可能会造成过度匹配问题。
- 适用数据类型: 数值型和标称型
在构造决策树时, 需要解决的第一个问题就是, 当前数据集上哪个特征在划分数据分类时起决定性作用。为了找到决定性的特征,划分出最好的结果,必须评估每个特征。
完成测试之后, 原始数据集就被划分为几个数据子集。这些数据子集会分布再第一个决策点的所有分支上。如果摸个分支下的数据属于同一类型,则当前已经正确地划分数据分类,无需进一步对数据集进行分割。如果数据子集内的数据不属于同一类型,则需要重复划分数据子集的过程。划分数据子集的算法和划分原始数据集的算法相同。持续整个过程知道所有具有相同类型的数据均在一个数据子集内。
创建分支的伪代码如下
| 1 | 检测数据集中的每个子项是否属于同一分类 |
| 2 |
if 属于同一匪类: return 类标签 |
| 3 |
else: |
| 4 | 寻找划分数据集的最好要特征 |
| 5 | 划分数据集 |
| 6 | 创建分支节点 |
| 7 |
for 每个划分的子集: 递归调用函数,并增加返回结果到分支节点中 |
| 8 | return 分支节点 |
决策树的一般流程
| 1 | 收集数据 | 可以使用任何方法 |
| 2 | 准备数据 | 树构造算法只适用于标称型数据,因此数值型数据必须离散化 |
| 3 | 分析数据 | 可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期 |
| 4 | 训练算法 | 构造树的数据结构 |
| 5 | 测试算法 | 使用经验树计算错误率 |
| 6 | 使用算法 | 此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义 |
一些决策树算法采用二分法划分数据。
信息增益
划分数据集的大原则是,将无序的数据变得更加有序。我们可以使用多种方法划分数据集,但是每种方法都有各自的优缺点。组织杂乱无章的数据的一种方法就是使用信息论度量信息,信息论是量化处理信息的分支科学。我们可以在划分数据前后使用信息论量化度量信息的内容。
在划分数据集之前之后信息发生的变化称为信息增益, 知道如何计算信息增益, 我们就可以计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。
集合信息的度量方式称为熵(entropy)。熵定义为信息的期望值。
信息的定义为: 如果待分类的事务可能华丰在多个分类中,则符号xi 的信息定义为: l(xi) = - log2p(xi), 其中p(xi)是选择该分类的概率。
为了计算熵,我们需要计算所有类别所有可能值包含的信息期望值: H = -Σni=1p(xi)log2p(xi),其中n使分类数目。
计算信息熵的python代码如下:
from math import log def calcShannonEnt(dataSet): numEntries = len(dataSet) labelCounts = {} for featVec in dataSet: currentLabel = feateVec[-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
熵越高,混合的数据也越多,我们可以在数据集中添加更多的分类,观察熵使如何变化的。
另一个度量集合无序的方法使基尼不纯度(Gini impurity),简单地说就是从一个数据集中随机选取子项,度量其被错误分类到其他分组里的概率。
划分数据集
按照给定特征划分数据集:
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(dateSet): 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) 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
递归简历决策树
从数据集构造决策树算法所需要的子功能模块,其工作原理如下: 得到原始数据集,然后基于最好的属性值划分数据集,由于特征值可能多余两个,因此可能存在大鱼两个分支的数据集划分。第一次划分之后,数据将被向下传递到书分支的下一个节点,在这个节点上,我们可以再次划分数据。因此我们可以采用递归原则处理数据集。递归结束的条件是,程序遍历完所有划分数据集的属性,或者每个分之下的所有实例都具有相同的分类。如果所有实例具有相同的分类,则得到一个叶子节点或者终止块。任何到达叶子节点的数据必然属于叶子节点的分类。
第一个结束条件是的算法可以终止,我们甚至可以设置算法可以划分的最大分组数目。分类的python代码如下:
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) 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
浙公网安备 33010602011771号