Q:上面的 newEntropy 为什么是根据子集计算的呢?
A :因为我们在根据一个特征计算香农熵的时候,该特征的分类值是相同,这个特征这个分类的香农熵为 0;
这就是为什么计算新的香农熵的时候使用的是子集。
构造树的数据结构
创建树的函数代码如下:
def createTree(dataSet, labels): classList = [example[-1] for example in dataSet] # 如果数据集的最后一列的第一个值出现的次数=整个集合的数量,也就说只有一个类别,就只直接返回结果就行 # 第一个停止条件:所有的类标签完全相同,则直接返回该类标签。 # count() 函数是统计括号中的值在list中出现的次数 if classList.count(classList[0]) == len(classList): return classList[0] # 如果数据集只有1列,那么最初出现label次数最多的一类,作为结果 # 第二个停止条件:使用完了所有特征,仍然不能将数据集划分成仅包含唯一类别的分组。 if len(dataSet[0]) == 1: return majorityCnt(classList) # 选择最优的列,得到最优列对应的label含义 bestFeat = chooseBestFeatureToSplit(dataSet) # 获取label的名称 bestFeatLabel = labels[bestFeat] # 初始化myTree myTree = {bestFeatLabel: {}} # 注:labels列表是可变对象,在PYTHON函数中作为参数时传址引用,能够被全局修改 # 所以这行代码导致函数外的同名变量被删除了元素,造成例句无法执行,提示'no surfacing' is not in list del(labels[bestFeat]) # 取出最优列,然后它的branch做分类 featValues = [example[bestFeat] for example in dataSet] uniqueVals = set(featValues) for value in uniqueVals: # 求出剩余的标签label subLabels = labels[:] # 遍历当前选择特征包含的所有属性值,在每个数据集划分上递归调用函数createTree() myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels) # print 'myTree', value, myTree return myTree (5)测试算法使用决策树执行分类
代码如下:
此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义。
构造决策树是很耗时的任务,即使很小的数据集也要花费几秒。如果用创建好的决策树解决分类问题就可以很快完成。
因此为了节省计算时间,最好能每次执行分类时调用已经构造好的决策树,为了解决这个问题,需要使用Python模块pickle序列化对象。序列化对象可以在磁盘上保存对象,并在需要的时候读取出来。任何对象都可以执行序列化,包括字典对象。
下面代码是使用pickle模块存储决策树:
def storeTree(inputTree, filename): impory pickle fw = open(filename, 'w') pickle.dump(inputTree, fw) fw.close() def grabTree(filename): import pickle fr = open(filename) return pickle.load(fr)通过上面的代码我们可以把分类器存储在硬盘上,而不用每次对数据分类时重新学习一遍,这也是决策树的优点之一。++K-近邻算法就无法持久化分类器++。
[1] 决策树维基百科: https://zh.wikipedia.org/wiki/%E5%86%B3%E7%AD%96%E6%A0%91
[2]《机器学习实战》 -- Peter Harrington
[3]《机器学习》 -- 周志华