zoukankan      html  css  js  c++  java
  • 机器学习实战-决策树

    决策树:

    1. 计算数据集的香农熵

     1 #计算给定数据集的香农熵
     2 def calcShannonEnt (dataset):
     3     # 求数据list的长度,表示计算参与训练的数据量
     4     numEnties = len(dataset)
     5     # 计算分类标签label出现的次数
     6     labelCounts={}
     7     for featVec in dataset:
     8         # 将当前实例的标签存储,即每一行数据的最后一个数据代表的是标签
     9         currentLabel= featVec[-1]
    10         # 为所有可能的分类创建字典,如果当前的键值不存在,则扩展字典并将当前键值加入自覅,每个键值都记录了
    11         #当前类别出现的次数
    12         if currentLabel not in labelCounts.keys():
    13          labelCounts[currentLabel]=0
    14         labelCounts[currentLabel]+=1
    15     # 对于label标签的占比,求出label标签label标签的香农熵
    16     shannonEnt=0.0
    17     #计算熵,求p(),累对数
    18     for key in labelCounts:
    19         # 使用所有类标签的发生频率计算类别出现的概率
    20         prob=float(labelCounts[key])/numEnties
    21         # log base 2 计算香农熵,以2为底求对数
    22         shannonEnt-=prob * log(prob,2)
    23     return shannonEnt

    2. 创建数据集

    1 # 创建数据集
    2 def createDataSet():
    3     dataSet = [[1,1,'yes'],
    4                [1,1,'yes'],
    5                [1,0,'no'],
    6                [0,1,'no'],
    7                [0,1,'no']]
    8     labels = ['no surfacing','flippers']
    9     return dataSet,labels

    3.  划分数据集:度量花费数据集的熵,以便判断当前是否正确地划分了数据集。我们将对每个特征划分数据集的结果计算一次信息熵,然后判断按照哪个特征划分数据集是最好的划分方式。

     1 # 按照给定特征划分数据集
     2 def splitDataSet(dataSet, index, value):
     3     """
     4     Desc:
     5         划分数据集
     6         splitDataSet(通过遍历dataSet数据集,求出index对应的colnum列的值为value的行)
     7         就是依据index列进行分类,如果index列的数据等于 value的时候,就要将 index 划分到我们创建的新的数据集中
     8     Args:
     9         dataSet  -- 数据集                 待划分的数据集
    10         index -- 表示每一行的index列        划分数据集的特征
    11         value -- 表示index列对应的value值   需要返回的特征的值。
    12     Returns:
    13         index 列为 value 的数据集【该数据集需要排除index列】
    14     """
    15     retDataSet = []
    16     # 目的是不要指定index列数据的新数据集
    17     for featVec in dataSet:
    18         if featVec[index] == value:
    19             # [:index]表示前index行,即若 index 为2,就是取 featVec 的前 index 行
    20             reduceFeatVec =featVec[:index]
    21             '''
    22             请百度查询一下: extend和append的区别
    23             list.append(object) 向列表中添加一个对象object
    24             list.extend(sequence) 把一个序列seq的内容添加到列表中
    25             1、使用append的时候,是将new_media看作一个对象,整体打包添加到music_media对象中。
    26             2、使用extend的时候,是将new_media看作一个序列,将这个序列和music_media序列合并,并放在其后面。
    27             result = []
    28             result.extend([1,2,3])
    29             print(result)
    30             result.append([4,5,6])
    31             print(result)
    32             result.extend([7,8,9])
    33             print(result)
    34             结果:
    35             [1, 2, 3]
    36             [1, 2, 3, [4, 5, 6]]
    37             [1, 2, 3, [4, 5, 6], 7, 8, 9]
    38             '''
    39             reduceFeatVec.extend(featVec[index+1:])
    40             # [index+1:]表示从跳过 index 的 index+1行,取接下来的数据
    41             # 收集结果值 index列为value的行【该行需要排除index列】
    42             retDataSet.append(reduceFeatVec)
    43     return retDataSet

    3. 选择最好的数据集划分方式。实现选取特征,划分数据集,计算得到最好的划分数据集特征。

     1 def chooseBsetFeatureToSplit (dataSet):
     2     """
     3     选择切分数据集的最佳特征
     4     :param dataSet: 需要切分的数据集
     5     :return: bestFeature:切分数据集的最优特征列
     6     """
     7     # 得到特征个数,求第一行有多少列的feature,我们知道数据的最后一列是label,所以不需要。
     8     numFeatures = len(dataSet[0])-1
     9     # 计算数据的label的信息熵
    10     baseEntropy = calcShannonEnt(dataSet)
    11     # 定义最优的信息增益值,以及最优的特征标号变量
    12     bestInfoGain =0.0; bestFeature = -1
    13     # 迭代所有的特征
    14     for i in range (numFeatures):
    15         #获取每一个实例的第i+1个feature,组成一个list集合。
    16         featList=[example[i] for example in dataSet]
    17         # 获取去重后的集合,使用set对list数据进行去重
    18         uniqueVals=set(featList)
    19         # 创建一个临时的信息熵
    20         newEntropy=0.0
    21         # 遍历某一列的value集合,计算该列的信息熵
    22         # 遍历当前特征中的所有唯一属性值,对每个唯一属性值划分一次数据集,计算数据集的新熵值,并对所有唯一特征值得到得到熵求和
    23         for value in uniqueVals:
    24             subDataSet=splitDataSet(dataSet,i,value)
    25             prob=len(subDataSet)/float(len(dataSet))
    26             newEntropy+=prob * calcShannonEnt(subDataSet)
    27         # gain是信息增益:划分数据前后的信息变化,获取信息熵最大的值
    28         # 信息增益是熵的减少或者是数据无序度的减少,最后,比较所有特征中的信息增益,返回最好特征划分的索引值。
    29         infoGain = baseEntropy-newEntropy
    30         print('infoGain=',infoGain,'bestFeature=',i,baseEntropy,newEntropy)
    31         if(infoGain>bestInfoGain):
    32             bestInfoGain=infoGain
    33             bestFeature=i
    34         return bestFeature

    4. 由于特征值可能多于2个,因此可能存在大于两个分支的数据集划分,第一次划分之后,数据将被向下传递到树分支的下一个支点,在这个节点上,我们可以再次划分数据。如果数据集已经处理了所有属性,但是类标签依然不是唯一的,此时我们需要决定定义该叶子节点,在这种情况下,我们通常会采用多数表决得到方法决定该叶子节点的分类。

    此时我们编写该功能,并加上import operator.

     1 def majorityCnt(classList):
     2     """
     3     选择出现次数最多的一个结果
     4     :param classList: label列的集合
     5     :return: bestFeature最优的特征列
     6     """
     7     classCount={}
     8     for vote in classList:
     9         if vote not in classCount.keys():
    10             classCount[vote]=0
    11         classCount[vote]+=1
    12     # 倒序排列classCount得到一个字典集合,然后取出第一个就是结果,即出现次数最多的结果
    13     sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    14     return sortedClassCount[0][0]

    5. 创建决策树

     1 def createTree(dataSet,labels):
     2     """
     3     创建决策树
     4     :param dataSet: 要创建决策树的训练数据集
     5     :param labels: 训练数据集中特征对应的含义的labels,不是目标变量
     6     :return:myTree:创建完成的决策树
     7     """
     8     # 获取所有类别
     9     classList=[example[-1] for example in dataSet]
    10     # 如果数据集的最后一类的第一个值出现的次数等于整个集合的数量,也就是说只有一个类别,就只直接返回结果就行
    11     if classList.count(classList[0])== len(classList):
    12         return classList[0]
    13     # 如果数据集只有一列,那么最初出现label次数最多的一类,作为结果
    14     if len(dataSet[0])==1:
    15         return majorityCnt(classList)
    16 
    17     # 选择最优的列,得到最优列对应的label含义
    18     bestFeat= chooseBsetFeatureToSplit(dataSet)
    19     # 获取label的名称
    20     bestFeatLabel =labels[bestFeat]
    21     #初始化myTree
    22     myTree={bestFeatLabel:{}}
    23     # lables列表是可变对象,在python函数中作为参数时传址引用,能够被全局修改
    24     del(labels[bestFeat])
    25     #取出最优列,将后他的branch做分类
    26     featValues=[example[bestFeat] for example in dataSet]
    27     uniqueVals=set(featValues)
    28     for value in uniqueVals:
    29         # 求出剩余的标签label,复制类标签,存在在新列表上
    30         subLabels=labels[:]
    31         # 遍历当前选择特征包含的所有属性值,在每个数据集划分上递归调用函数createTree()
    32         myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
    33     return myTree

     6. 使用决策树进行分类。

     1 def classify(inputTree,featLabels,testVec):
     2     """
     3     对新数据进行分类
     4     :param inputTree: 已经训练好的决策树模型
     5     :param featLabels: Feature标签对应的名称,不是目标变量
     6     :param testVec: 测试输入的数据
     7     :return: 分类的结果值,需要映射label知道名称
     8     """
     9     #获取tree的根节点对于key值
    10     firstStr=list(inputTree.keys())[0]
    11     #通过key得到根节点对应的value
    12     secondDict=inputTree[firstStr]
    13     # 判断根节点名称获取根节点在label中的先后顺序,这样就知道输入的testVec怎么开始对照树来做分类
    14     featIndex=featLabels.index(firstStr)
    15     #测试数据,找到根节点对应的label位置,也就知道从输入的数据的第几位来开始分类
    16     key=testVec[featIndex]
    17     valueOfFeat=secondDict[key]
    18     #判断分枝是否结束,判断valueOfFeat是否是dict类型
    19     if isinstance(valueOfFeat,dict):
    20         classLabel=classify(valueOfFeat,featLabels,testVec)
    21     else:
    22         classLabel=valueOfFeat
    23     return classLabel

    7. 测试数据

     1 def fishTest():
     2     """
     3     Desc:
     4         对动物是否是鱼类分类的测试函数,并将结果使用 matplotlib 画出来
     5     Args:
     6         None
     7     Returns:
     8         None
     9     """
    10     # 1.创建数据和结果标签
    11     myDat, labels = createDataSet()
    12     # print(myDat, labels)
    13 
    14     # 计算label分类标签的香农熵
    15     # calcShannonEnt(myDat)
    16 
    17     # # 求第0列 为 1/0的列的数据集【排除第0列】
    18     # print('1---', splitDataSet(myDat, 0, 1))
    19     # print('0---', splitDataSet(myDat, 0, 0))
    20 
    21     # # 计算最好的信息增益的列
    22     # print(chooseBestFeatureToSplit(myDat))
    23 
    24     import copy
    25     myTree = createTree(myDat, copy.deepcopy(labels))
    26     print(myTree)
    27     # [1, 1]表示要取的分支上的节点位置,对应的结果值
    28     print(classify(myTree, labels, [1, 1]))

    测试结果为yes

    相应的github地址:https://github.com/CynthiaWendy/Machine-Learning-in-Action-DecisionTree

  • 相关阅读:
    SPRING IN ACTION 第4版笔记-第八章Advanced Spring MVC-001- 配置SpringFlow(flow-executor、flow-registry、FlowHandlerMapping、FlowHandlerAdapter)
    SPRING IN ACTION 第4版笔记-第七章Advanced Spring MVC-006- 如何保持重定向的request数据(用model、占位符、RedirectAttributes、model.addFlashAttribute("spitter", spitter);)
    SPRING IN ACTION 第4版笔记-第七章Advanced Spring MVC-005- 异常处理@ResponseStatus、@ExceptionHandler、@ControllerAdvice
    SPRING IN ACTION 第4版笔记-第七章Advanced Spring MVC-004- 处理上传文件
    SPRING IN ACTION 第4版笔记-第七章Advanced Spring MVC-003- 上传文件multipart,配置StandardServletMultipartResolver、CommonsMultipartResolver
    SPRING IN ACTION 第4版笔记-第七章Advanced Spring MVC-002- 在xml中引用Java配置文件,声明DispatcherServlet、ContextLoaderListener
    SPRING IN ACTION 第4版笔记-第七章Advanced Spring MVC-001- DispatcherServlet的高级配置(ServletRegistration.Dynamic、WebApplicationInitializer)
    Swift
    Swift
    用POP动画引擎实现弹簧动画(POPSpringAnimation)
  • 原文地址:https://www.cnblogs.com/CynthiaWendy/p/11065586.html
Copyright © 2011-2022 走看看