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) return myTree
def chooseBestFeatureToSplit(dataSet): """chooseBestFeatureToSplit(选择最好的特征) Args: dataSet 数据集 Returns: bestFeature 最优的特征列 """ # 求第一行有多少列的 Feature, 最后一列是label列嘛 numFeatures = len(dataSet[0]) - 1 # 数据集的原始信息熵 baseEntropy = calcShannonEnt(dataSet) # 最优的信息增益值, 和最优的Featurn编号 bestInfoGain, bestFeature = 0.0, -1 # iterate over all the features for i in range(numFeatures): # create a list of all the examples of this feature # 获取对应的feature下的所有数据 featList = [example[i] for example in dataSet] # get a set of unique values # 获取剔重后的集合,使用set对list数据进行去重 uniqueVals = set(featList) # 创建一个临时的信息熵 newEntropy = 0.0 # 遍历某一列的value集合,计算该列的信息熵 # 遍历当前特征中的所有唯一属性值,对每个唯一属性值划分一次数据集,计算数据集的新熵值,并对所有唯一特征值得到的熵求和。 for value in uniqueVals: subDataSet = splitDataSet(dataSet, i, value) # 计算概率 prob = len(subDataSet) / float(len(dataSet)) # 计算信息熵 newEntropy += prob * calcShannonEnt(subDataSet) # gain[信息增益]: 划分数据集前后的信息变化, 获取信息熵最大的值 # 信息增益是熵的减少或者是数据无序度的减少。最后,比较所有特征中的信息增益,返回最好特征划分的索引值。 infoGain = baseEntropy - newEntropy print('infoGain=', infoGain, 'bestFeature=', i, baseEntropy, newEntropy) if (infoGain > bestInfoGain): bestInfoGain = infoGain bestFeature = i return bestFeature
def chooseBestFeatureToSplit(dataSet): numFeatures = len(dataSet[0]) - 1 #前提:数据是由列表元素组成的列表,列表元素具有相同的长度;除去标签,假设有两个特征 baseEntropy = calcShannonEnt.calcShannonEnt(dataSet) #计算出最初的无序度量度 bestInfoGain = 0.0 bestFeature = -1 for i in range(numFeatures): #2;i代表索引值;第几个特征 featList = [example[i] for example in dataSet] #除去标签,提取出了所有的特征 uniqueVals = set(featList) #set:每个值互不相同;除去相同的特征 newEntropy = 0.0 #以上代码创建出了唯一的分类标签列表;将数据集中所有i个特征值写入新的列表中 for value in uniqueVals: subDataSet = splitDataSet.splitDataSet(dataSet, i, value) #i代表第几个特征 prob = len(subDataSet) / float(len(dataSet)) newEntropy += prob * calcShannonEnt.calcShannonEnt(subDataSet) # 这个for循环计算每一种划分方法的信息熵; 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): #count用来计数 return classList[0] #第一个停止条件:类别完全相同则灵芝划分 if len(dataSet[0]) == 1: return majorityCnt.majorityCnt(classList) # 第二个停止条件:遍历完所有特征是返回出现次数最多的 bestFeat = chooseBestFeatureToSplit.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.splitDataSet(dataSet, bestFeat, value), subLabels) return myTree
def createTree(dataSet, labels): from majorityVote import majorityVote from chooseBestFeatureToSplit import chooseBestFeatureToSplit from splitDataSet import splitDataSet classList = [example[0] for example in dataSet] #提取dataSet的样本标签集 if classList.count(classList[0]) == len(classList): #dataSet只有一类 return classList[0] if len(dataSet[0]) == 1: return majorityVote(classList) #当递归算法使用完所有特征后,这里不用单纯的一类作返回值,而是以majorityVote投票选多数类作返回值 Trainlabels = labels.copy() #不要直接用labels,copy一下,要不会破坏原数据 bestFeature = chooseBestFeatureToSplit(dataSet) bestFeatureLabel = Trainlabels[bestFeature - 1] #这里和书中不同,要-1 tree = {bestFeatureLabel: {}} #结构初始化 del (Trainlabels[bestFeature - 1]) #已写入树结构的标签可以去掉了 #这里和书中不同,要-1 #以下步骤为基于目前的最佳分割特征来分割现有的数据集 featureValues = [example[bestFeature] for example in dataSet] featureValuesSet = set(featureValues) for value in featureValues: subLabels = Trainlabels[:] tree[bestFeatureLabel][value] = createTree( splitDataSet(dataSet, bestFeature, value), subLabels) #用递归的方法建立嵌套字典 #字典先成型的是最底下的叶节点,然后再自下而上往上层嵌套构造的整个树 return tree
def chooseBestFeatureToSplit(dataSet): from shannonEnt import calShannonEnt from splitDataSet import splitDataSet numOfFeature = len(dataSet[0]) - 1 #减1是因为第一列是标签,不是特征 baseEnrtopy = calShannonEnt(dataSet) #在子函数调用自制模组只有这样不报错...不懂 bestInfoGain = 0.0 bestFeature = -1 #初始化 for indexOfFeature in range(1, numOfFeature + 1): featureValueList = [example[indexOfFeature] for example in dataSet] featureValueSet = set(featureValueList) #取第IndexOfFeature个特征所右可能的取值 newEntropy = 0.0 for featureValue in featureValueSet: subDataSet = splitDataSet(dataSet, indexOfFeature, featureValue) prob = len(subDataSet) / float(len(dataSet)) newEntropy += prob * calShannonEnt(subDataSet) infoGain = baseEnrtopy - newEntropy if (infoGain > bestInfoGain): bestInfoGain = infoGain bestFeature = indexOfFeature return bestFeature