我的编程空间,编程开发者的网络收藏夹
学习永远不晚

ID3决策树及Python实现(详细)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

ID3决策树及Python实现(详细)

目录

一、划分特征的评价指标:

二、决策树学习算法伪代码:

三、决策树生成实例:

四、Python实现ID3决策树:


一、划分特征的评价指标:

1、信息熵 Ent(D):

信息熵,是度量样本集合纯度的一种指标,Ent(D)的值越小,则样本集D的纯度越高;

2、信息增益 Gain(D,a):

信息增益越大,则意味着使用属性a来划分所获得的“纯度提升”越大;ID3决策树算法就是基于信息增益来划分属性,下面介绍ID3决策树的构建过程;

公式中各变量说明:

D:样本集;

y:标签(比如好瓜、坏瓜);

pk:某一类样本占总样本数的比例;

V:属性的取值(比如纹理属性有3种取值:清晰、稍糊、模糊);

Dv:属性值==V从样本集D划分出的一个样本子集;

二、决策树学习算法伪代码:

决策树的生成是一个递归的过程,在决策树基本算法中,有三种情形会导致递归返回

  1. 当前结点包含的样本全属于同一类别,无需划分;
  2. 当前属性集为空,或是所有样本在所有属性上取值相同,无法划分;
  3. 当前结点包含的样本集合为空,不能划分; 

三、决策树生成实例:

3.1 首先获取一个训练样本集D,作为决策树的训练依据:

3.2 计算信息增益:

计算信息熵 Ent(D)

计算当前特征集合 {色泽,根蒂,敲声,纹理,脐部,触感} 中各个特征a的信息增益Gain(D,a)

 以“色泽”为例计算Gain(D,色泽):

色泽的取值:{青绿,乌黑,浅白},使用“色泽”特征对D划分可以得到3个子集:D1(色泽=青绿)={1,4,6,10,13,17},D2(色泽=乌黑)={2,3,7,8,9,15},D1(色泽=浅白)={5,11,12,14,16},计算划分子集后分支结点的熵 :

所以,得到Gain(D,色泽)

 同理,计算其他特征的信息增益Gain(D,a)

3.3 选取最优信息增益,选取最优划分特征:

因为Gain(D,纹理)最大,所以选取“纹理”作为本轮划分的最优划分特征,继而可以得到基于“纹理”的根节点划分:

3.4 决策树算法再对每个分支进一步划分(递归):

将每个分支可以看成一个新的样本集,进行进一步的划分,在计算各特征信息增益时,需要将上一轮选出的最优特征在样本中去掉,不需要再对该特征进行比较。

就比如D1={1,2,3,4,5,6,8,10,15},特征集合={色泽,根蒂,敲声,脐部,触感}。基于D1计算出各特征的信息增益Gain(D1,a):

继续选取最大的特征信息增益,选出最优划分特征,即重复3.3步骤,递归实现决策树的建立;

3.5 生成最终的决策树:

四、Python实现ID3决策树:

总样本集:

['青绿','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],['乌黑','蜷缩','沉闷','清晰','凹陷','硬滑','好瓜'],['乌黑','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],['青绿','蜷缩','沉闷','清晰','凹陷','硬滑','好瓜'],                ['青绿','稍蜷','浊响','清晰','稍凹','软粘','好瓜'],               ['乌黑','稍蜷','浊响','稍糊','稍凹','软粘','好瓜'],                ['乌黑','稍蜷','浊响','清晰','稍凹','硬滑','好瓜'],['浅白','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],['浅白','蜷缩','浊响','模糊','平坦','硬滑','坏瓜'],             ['乌黑','稍蜷','沉闷','稍糊','稍凹','硬滑','坏瓜'],['青绿','硬挺','清脆','清晰','平坦','软粘','坏瓜'],['浅白','蜷缩','浊响','模糊','平坦','软粘','坏瓜'],['青绿','稍蜷','浊响','稍糊','凹陷','硬滑','坏瓜'],  ['浅白','稍蜷','沉闷','稍糊','凹陷','硬滑','坏瓜'],['浅白','硬挺','清脆','模糊','平坦','硬滑','坏瓜'],['乌黑','稍蜷','浊响','清晰','稍凹','软粘','坏瓜'],['青绿','蜷缩','沉闷','稍糊','稍凹','硬滑','坏瓜']

下面从总样本种提取序号5、12、17为验证集,剩下为训练集进行训练决策树;

(1)训练集:

['青绿','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],['乌黑','蜷缩','沉闷','清晰','凹陷','硬滑','好瓜'],['乌黑','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],['青绿','蜷缩','沉闷','清晰','凹陷','硬滑','好瓜'],['乌黑','稍蜷','浊响','稍糊','稍凹','软粘','好瓜'],['乌黑','稍蜷','浊响','清晰','稍凹','硬滑','好瓜'],['浅白','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],['浅白','蜷缩','浊响','模糊','平坦','硬滑','坏瓜'],['乌黑','稍蜷','沉闷','稍糊','稍凹','硬滑','坏瓜'],['浅白','蜷缩','浊响','模糊','平坦','软粘','坏瓜'],['青绿','稍蜷','浊响','稍糊','凹陷','硬滑','坏瓜'],['浅白','稍蜷','沉闷','稍糊','凹陷','硬滑','坏瓜'],['浅白','硬挺','清脆','模糊','平坦','硬滑','坏瓜'],['青绿','蜷缩','沉闷','稍糊','稍凹','硬滑','坏瓜']

(2)验证集:

['青绿','稍蜷','浊响','清晰','稍凹','软粘'], ['好瓜']['青绿','硬挺','清脆','清晰','平坦','软粘'], ['坏瓜']['乌黑','稍蜷','浊响','清晰','稍凹','软粘'], ['坏瓜']

下面编写各个函数,每个函数有特定的功能,代码的分析过程已在code后注释。

1 构建样本集:

#? 构建数据集#  返回一个元组 (dataSet,labels)def createDataSet():    # 创造示例数据    dataSet=[['青绿','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],             ['乌黑','蜷缩','沉闷','清晰','凹陷','硬滑','好瓜'],             ['乌黑','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],             ['青绿','蜷缩','沉闷','清晰','凹陷','硬滑','好瓜'], ['青绿','稍蜷','浊响','清晰','稍凹','软粘','好瓜'],['乌黑','稍蜷','浊响','稍糊','稍凹','软粘','好瓜'], ['乌黑','稍蜷','浊响','清晰','稍凹','硬滑','好瓜'],                          ['乌黑','稍蜷','沉闷','稍糊','稍凹','硬滑','坏瓜'],             ['青绿','硬挺','清脆','清晰','平坦','软粘','坏瓜'],             ['浅白','蜷缩','浊响','模糊','平坦','软粘','坏瓜'],             ['青绿','稍蜷','浊响','稍糊','凹陷','硬滑','坏瓜'],               ['浅白','稍蜷','沉闷','稍糊','凹陷','硬滑','坏瓜'],             ['乌黑','稍蜷','浊响','清晰','稍凹','软粘','坏瓜'],             ['青绿','蜷缩','沉闷','稍糊','稍凹','硬滑','坏瓜']]    labels = ['色泽','根蒂','敲声','纹理','脐部','触感']  #六个特征    return dataSet,labels

函数作用:用于构建训练集

变量说明:

  1. dataSet:样本集
  2. labels:所有特征

4.2 计算信息熵:

#? 计算信息熵#  返回输入样本集dataSet的信息熵 Entfrom math import logdef calEnt(dataSet):    sampleCounts=len(dataSet)   # 样本集的样本数    labelCounts={}              # key为标签值label(好瓜、坏瓜),value为对应标签key在样本集中出现的次数    for sample in dataSet:      # 遍历样本集dataSet中每个样本sample        label=sample[-1]        # 标签label为样本sample的最后一个元素值        if label not in labelCounts.keys():     # 如果该标签label不在字典labelCounts的key值中            labelCounts[label]=0                # 则新增该key,并赋初值0        labelCounts[label]+=1   # 对遍历到的每个sample统计其所属标签的个数    Ent=0.0     # 信息熵初始化    for key in labelCounts:        pro=float(labelCounts[key])/sampleCounts    # 具体标签占总样本数的比例pro        Ent-=pro*log(pro,2)     # 计算样本集dataSet的信息熵Ent    return Ent

函数作用:计算样本集dataSet的信息熵E(dataSet)

变量说明:

  1. dataSet:传入的样本集
  2. sampleCounts:样本集中的样本数
  3. labelCounts:key为标签值(好瓜/坏瓜),value为对应标签key在样本集中出现的次数
  4. sample:具体样本
  5. label:标签(好瓜、坏瓜)
  6. pro:具体标签占总样本数的比例
  7. Ent:样本集dataSet的熵 Ent(D)

4.3 按给定的特征值划分出样本子集:

#? 按给定特征值划分出样本子集#  指定特征列的索引index,对特征值==value的样本划分出来为一个样本子集retDataSet,并对这些样本的value去掉,返回样本子集 retDataSetdef splitDataSet(dataSet,index,value):      # index是指定特征列的索引,value是该特征下的某一特征值    retDataSet=[]    for sample in dataSet:                  # 遍历样本集dataSet中的具体样本sample        if sample[index]==value:            # 找到目标特征值value的索引            # 去除特征值==value这些样本的vlaue值            reducedSample=sample[:index]            # 剪下目标索引前的列表            reducedSample.extend(sample[index+1:])  # 将目标索引后的列表添加到索引前列表的后面            retDataSet.append(reducedSample)        # 将sample[index]==value并去除该vlaue的样本添加到retDataSet样本集中    return retDataSet

函数作用:指定特征列的索引index,对样本集中特征值==value的具体样本sample划分出来,组成一个dataSet的样本子集retDataSet(并将这些样本中的这些value去掉,去掉sample[index]的目的是因为下轮比较各特征信息增益Gain从而获得最大信息增益bestGain(决定最优划分特征bestFeature)时,不能将已选出的最优特征放在比较队列中)

变量说明:

  1. dataSet:传入的样本集
  2. index:指定特征列的索引
  3. value:指定特征的某一特征值
  4. sample:dataSet的具体样本
  5. reducedSample:去除value后的具体样本(该样本sample[index]==value)
  6. retDataSet:按指定某一特征值划分出的样本子集

4.4 选取当前样本集下的最优划分特征索引:

#? 选取当前样集下的最优划分特征索引#  返回最优划分特征的索引 bestFeatureIndexdef chooseBestFeatureToSplit(dataSet):    featureCounts=len(dataSet[0])-1     # 获取当前样本集的特征个数,-1是因为最后一列是标签    baseEnt=calEnt(dataSet)             # 计算当前样本集的信息熵Ent(D)    bestGain=0.0;bestFeatureIndex=-1    # 初始化最优信息增益bestGain、最优特征bestFeature    for i in range(featureCounts):      # 遍历每个特征,求各自的信息增益Gain        featValList=[sample[i] for sample in dataSet]   # 第i个特征下所有样本出现的特征值(有重复)        uniqueVals=set(featValList)                     # 第i个特征的可能特征值(无重复)        newEnt=0.0          # 初始化信息熵        for value in uniqueVals:            subDataSet=splitDataSet(dataSet,i,value)    # 根据特定的特征值value划分出的样本子集            pro=len(subDataSet)/float(len(dataSet))     # 划分出的样本子集占总样本数的比例            newEnt+=pro*calEnt(subDataSet)              # 计算各特征值的熵并加和        Gain=baseEnt-newEnt # 计算信息增益Gain(D,a)        if(Gain>bestGain):      # 求最大的信息增益Gain            bestGain=Gain            bestFeatureIndex=i  # 获取最优划分特征的索引    return bestFeatureIndex

函数作用:计算各特征的信息增益Gain(dataset,feature),从而选出最优划分特征bestFeature,最后返回最优划分特征的索引bestFeatureIndex;

变量说明:

  1. dataSet:传入的样本集
  2. featureCounts:当前样本集中特征的个数
  3. baseEnt:当前样本集的熵 Ent(D)
  4. bestGain:各特征中最大的信息增益 Gain(dataSet,bestFeature)
  5. bestFeatureIndex:最优划分特征的索引列号
  6. sample[i]:具体样本第i个特征值
  7. featureValList:第i个特征下所有样本中出现的特征值(有重复值)
  8. uniqueVals:第i个特征的可能特征值(无重复值)
  9. newEnt:不同特征值下的熵 Ent(Di)
  10. subDataSet:根据特定的特征值value划分出的样本子集
  11. pro:样本子集占总样本数的比例
  12. Gain:各个特征的信息增益Gain(D,a)

4.5 求样本集中出现次数最多的标签:

#? 求样本集中出现次数最多的标签#  用于叶子节点的取值,返回样本集中出现次数最多的标签 sortedLabelCounts[0][0]import operatordef majorLabel(labelList):    labelCounts={}      # key为标签(好瓜/坏瓜),value为标签在labelList中出现的次数    for label in labelList:     # 遍历所有样本的标签        if label not in labelCounts.keys(): # 如果该标签不在labelCounts的key值中            labelCounts[label]=0            # 则增加该key值,并赋初值=0        labelCounts[label]+=1               # 对labelCounts中已有的标签计数+1    sortedLabelCounts=sorted(labelCounts.items(),key=operator.itemgetter(1),reverse=True)   # 根据value值逆序排序labelCounts    return sortedLabelCounts[0][0]          # 返回第一个元素的第一个元素(标签)

函数作用:选取叶子结点的取值,返回样本集中出现次数最多的标签(好瓜/坏瓜)sortedLabelCounts[0][0];

变量说明:

  1. labelList:返回样本集中所有样本的标签(有重复值)
  2. labelCounts:字典,key为标签,value为该标签key在labelList中出现的次数
  3. label:具体标签(好瓜/坏瓜)
  4. labelCounts.keys():labelCounts的key值
  5. labelCounts[label]:labelCounts中key值==label对应的value值
  6. sortedLabelCounts:根据value值,逆序排列labelCounts字典
  7. sotredLabelCounts[0][0]:样本集中出现次数最多的标签

4.6 递归生成决策树:

#? 生成决策树 主方法#  递归生成决策树 decisionTree#  递归是逐级由深向浅的返回def createTree(dataSet,labels):    labelList=[sample[-1] for sample in dataSet]    # 返回当前样本集dataSet中所有样本的标签(有重复值列表)    # 跳出递归,生成叶子节点(好瓜/坏瓜)    if labelList.count(labelList[0])==len(labelList):   # 如果labelList中的标签完全相同        return labelList[0] # 则直接返回该标签    if len(dataSet[0])==1:              # 如果当前样本集dataSet的样本长度==1(只剩最后一列标签,无特征可供继续划分又不满足所有标签相同)        return majorLabel(labelList)    # 就返回出现次数最多的标签作为叶子节点        bestFeatureIndex=chooseBestFeatureToSplit(dataSet)  # 获取当前样本集dataSet最优划分特征的索引    bestFeature=labels[bestFeatureIndex]                # 获取当前样本集dataSet的最优划分特征    decisionTree={bestFeature:{}}   # 字典存储决策树的信息    del(labels[bestFeatureIndex])   # 删除已经选出的特征    featureVals=[sample[bestFeatureIndex] for sample in dataSet] # 样本集中所有样本中的最优特征对应的特征值组成的列表(有重复值)    uniqueVals=set(featureVals)     # 最优特征对应的所有可能取值(无重复值)    for value in uniqueVals:        # 遍历最优特征所有可能的取值value        subLabels=labels[:]         # 将最优特征去除后的特征列表传递给subLabels        decisionTree[bestFeature][value]=createTree(splitDataSet(dataSet,bestFeatureIndex,value),subLabels)  # 递归生成decisionTree    return decisionTree

函数作用:递归生成决策树 decisionTree

变量说明:

  1. dataSet:传入的样本集
  2. labels:传入的特征列表
  3. labelList:存放样本集dataSet中所有样本的标签(有重复值)
  4. sample:样本集的具体样本
  5. labelList[0]:第一个样本的标签
  6. dataSet[0]:样本集中的第一个样本
  7. majorLabel(labelList):样本集中出现次数最多的标签
  8. bestFeatureIndex:当前样本集中最优划分特征的索引列
  9. bestFeature:当前样本集中最优的划分特征
  10. labels[bestFeatureIndex]:最优划分特征索引对应的具体特征
  11. decisionTree:生成的决策树
  12. featureVals:样本集dataSet中最优特征对应的所有特征值(有重复值)
  13. uniqueVals:最优特征对应的可能取值(无重复值)
  14. value:最优特征对应的具体取值
  15. subLabels:去除最优特征后的特征列表

4.7 对决策样本进行分类:

#? 对验证样本进行分类#  返回一个对样本分类后的标签classLabeldef classify(decisionTree,features,testSample):rootFeature=list(decisionTree.keys())[0]        # rootFeature:根节点是何种特征rootDict=decisionTree[rootFeature]              # rootDict为根节点的value值,是一个字典rootFeatureIndex=features.index(rootFeature)    # 获取根节点在特征列表中的索引for value in rootDict.keys():               # value为特征rootFeature的不同取值,并遍历valueif testSample[rootFeatureIndex]==value:     # 如果待测样本的该特征的特征值==valueif type(rootDict[value])==dict:     # 如果该特征值value对应的value'是一个字典classLabel=classify(rootDict[value],features,testSample)    # 则需要递归继续向决策树的下面结点查询else:   # 如果该特征值value对应的value'是一个单独的值(标签)classLabel=rootDict[value]      # 则该值就是要找的标签return classLabel   # 返回该样本testSample的标签

函数作用:对传入的待测样本testSample根据已生成的决策树decisionTree计算出该样本的标签(好瓜/坏瓜),返回该标签 classLabel

变量说明:

  1. decisionTree:某一结点出发的决策树
  2. features:所有特征列表
  3. testSample:待测试样本
  4. decisionTree.keys():(某一特征值下)对应根结点
  5. decisionTree[rootFeature]:根节点对应的各个分支,字典
  6. rootFeature:根节点(如纹理)
  7. rootDict:根节点下的分支,字典(纹理结点对应的三个分支:模糊、清晰、稍糊)
  8. rootFeatureIndex:节点在特征列表features中的索引;
  9. value:以根节点为特征的不同特征取值(如模糊/清晰/稍糊)
  10. testSample[rootFeatureIndex]:待测试样本中以根节点为特征对应的具体特征值
  11. rootDict[value]:具体特征值对应的value(可能是一个字典/标签)
  12. classLabel:该待测试样本计算出的标签

4.8 执行:

if __name__=='__main__':    # 如果在当前模块/文件下执行,将会指定下述代码    dataSet, labels=createDataSet()    decisionTree=createTree(dataSet, labels)    print(f"\ndecisionTree={decisionTree}\n")     # 输出决策树模型结果    # 验证集    features=  ['色泽','根蒂','敲声','纹理','脐部','触感']  # 特征列表         testSample=['浅白','蜷缩','浊响','清晰','凹陷','硬滑']  # 待测样本    print(f"测试结果1sampleLabel= {classify(decisionTree,features,testSample)}\n")   # 输出测试结果    features=  ['色泽','根蒂','敲声','纹理','脐部','触感']  # 特征列表         testSample=['浅白','硬挺','清脆','模糊','平坦','硬滑']  # 待测样本    print(f"测试结果2sampleLabel= {classify(decisionTree,features,testSample)}\n")   # 输出测试结果    features=  ['色泽','根蒂','敲声','纹理','脐部','触感']  # 特征列表         testSample=['浅白','蜷缩','浊响','模糊','平坦','硬滑']  # 待测样本    print(f"测试结果3sampleLabel= {classify(decisionTree,features,testSample)}\n")   # 输出测试结果

函数说明:执行主函数代码,利用上述各函数打印出最终的决策树decisionTree并且对验证集待测样本进行测试检验

变量说明:

  1. features:特征列表
  2. testSample:待测试样本

4.9 运行结果:

decisionTree={'纹理': {'稍糊': {'触感': {'硬滑': '坏瓜', '软粘': '好瓜'}}, '清晰': {'根蒂': {'硬挺': '坏瓜', '蜷缩': '好瓜', '稍蜷': {'色泽': {'青绿': '好瓜', '乌黑': {'触感': {'硬滑': '好瓜', '软粘': '坏瓜'}}}}}}, '模糊': '坏瓜'}}     测试结果1sampleLabel= 好瓜测试结果2sampleLabel= 坏瓜测试结果3sampleLabel= 坏瓜

决策树decisionTree:

{'纹理':     {'模糊': '坏瓜',      '清晰': {'根蒂':                 {'稍蜷': {'色泽': {'乌黑': {'触感':             {'软粘': '坏瓜',              '硬滑': '好瓜'}},  '青绿': '好瓜'}},                  '硬挺': '坏瓜',                  '蜷缩': '好瓜'}},      '稍糊': {'触感':                 {'软粘': '好瓜',                  '硬滑': '坏瓜'}}}}

可视化为树状结构为:

10 实现决策树的总代码:

#! Decision Tree(ID3算法 信息增益Gain)#? 构建数据集#  返回一个元组 (dataSet,labels)def createDataSet():    # 创造示例数据    dataSet=[['青绿','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],             ['乌黑','蜷缩','沉闷','清晰','凹陷','硬滑','好瓜'],             ['乌黑','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],             ['青绿','蜷缩','沉闷','清晰','凹陷','硬滑','好瓜'], ['青绿','稍蜷','浊响','清晰','稍凹','软粘','好瓜'],['乌黑','稍蜷','浊响','稍糊','稍凹','软粘','好瓜'], ['乌黑','稍蜷','浊响','清晰','稍凹','硬滑','好瓜'],                          ['乌黑','稍蜷','沉闷','稍糊','稍凹','硬滑','坏瓜'],             ['青绿','硬挺','清脆','清晰','平坦','软粘','坏瓜'],             ['浅白','蜷缩','浊响','模糊','平坦','软粘','坏瓜'],             ['青绿','稍蜷','浊响','稍糊','凹陷','硬滑','坏瓜'],               ['浅白','稍蜷','沉闷','稍糊','凹陷','硬滑','坏瓜'],             ['乌黑','稍蜷','浊响','清晰','稍凹','软粘','坏瓜'],             ['青绿','蜷缩','沉闷','稍糊','稍凹','硬滑','坏瓜']]    labels = ['色泽','根蒂','敲声','纹理','脐部','触感']  #六个特征    return dataSet,labels#? 计算信息熵#  返回输入样本集dataSet的信息熵 Entfrom math import logdef calEnt(dataSet):    sampleCounts=len(dataSet)   # 样本集的样本数    labelCounts={}              # key为标签值label(好瓜、坏瓜),value为对应标签key在样本集中出现的次数    for sample in dataSet:      # 遍历样本集dataSet中每个样本sample        label=sample[-1]        # 标签label为样本sample的最后一个元素值        if label not in labelCounts.keys():     # 如果该标签label不在字典labelCounts的key值中            labelCounts[label]=0                # 则新增该key,并赋初值0        labelCounts[label]+=1   # 对遍历到的每个sample统计其所属标签的个数    Ent=0.0     # 信息熵初始化    for key in labelCounts:        pro=float(labelCounts[key])/sampleCounts    # 具体标签占总样本数的比例pro        Ent-=pro*log(pro,2)     # 计算样本集dataSet的信息熵Ent    return Ent#? 按给定特征值划分出样本子集#  指定特征列的索引index,对特征值==value的样本划分出来为一个样本子集retDataSet,并对这些样本的value去掉,返回样本子集 retDataSetdef splitDataSet(dataSet,index,value):      # index是指定特征列的索引,value是该特征下的某一特征值    retDataSet=[]    for sample in dataSet:                  # 遍历样本集dataSet中的具体样本sample        if sample[index]==value:            # 找到目标特征值value的索引            # 去除特征值==value这些样本的vlaue值            reducedSample=sample[:index]            # 剪下目标索引前的列表            reducedSample.extend(sample[index+1:])  # 将目标索引后的列表添加到索引前列表的后面            retDataSet.append(reducedSample)        # 将sample[index]==value并去除该vlaue的样本添加到retDataSet样本集中    return retDataSet#? 选取当前样集下的最优划分特征索引#  返回最优划分特征的索引 bestFeatureIndexdef chooseBestFeatureToSplit(dataSet):    featureCounts=len(dataSet[0])-1     # 获取当前样本集的特征个数,-1是因为最后一列是标签    baseEnt=calEnt(dataSet)             # 计算当前样本集的信息熵Ent(D)    bestGain=0.0;bestFeatureIndex=-1    # 初始化最优信息增益bestGain、最优特征bestFeature    for i in range(featureCounts):      # 遍历每个特征,求各自的信息增益Gain        featValList=[sample[i] for sample in dataSet]   # 第i个特征下所有样本出现的特征值(有重复)        uniqueVals=set(featValList)                     # 第i个特征的可能特征值(无重复)        newEnt=0.0          # 初始化信息熵        for value in uniqueVals:            subDataSet=splitDataSet(dataSet,i,value)    # 根据特定的特征值value划分出的样本子集            pro=len(subDataSet)/float(len(dataSet))     # 划分出的样本子集占总样本数的比例            newEnt+=pro*calEnt(subDataSet)              # 计算各特征值的熵并加和        Gain=baseEnt-newEnt # 计算信息增益Gain(D,a)        if(Gain>bestGain):      # 求最大的信息增益Gain            bestGain=Gain            bestFeatureIndex=i  # 获取最优划分特征的索引    return bestFeatureIndex#? 求样本集中出现次数最多的标签#  用于叶子节点的取值,返回样本集中出现次数最多的标签 sortedLabelCounts[0][0]import operatordef majorLabel(labelList):    labelCounts={}      # key为标签(好瓜/坏瓜),value为标签在labelList中出现的次数    for label in labelList:     # 遍历所有样本的标签        if label not in labelCounts.keys(): # 如果该标签不在labelCounts的key值中            labelCounts[label]=0            # 则增加该key值,并赋初值=0        labelCounts[label]+=1               # 对labelCounts中已有的标签计数+1    sortedLabelCounts=sorted(labelCounts.items(),key=operator.itemgetter(1),reverse=True)   # 根据value值逆序排序labelCounts    return sortedLabelCounts[0][0]          # 返回第一个元素的第一个元素(标签)#? 生成决策树 主方法#  递归生成决策树 decisionTree#  递归是逐级由深向浅的返回def createTree(dataSet,labels):    labelList=[sample[-1] for sample in dataSet]    # 返回当前样本集dataSet中所有样本的标签(有重复值列表)    # 跳出递归,生成叶子节点(好瓜/坏瓜)    if labelList.count(labelList[0])==len(labelList):   # 如果labelList中的标签完全相同        return labelList[0] # 则直接返回该标签    if len(dataSet[0])==1:              # 如果当前样本集dataSet的样本长度==1(只剩最后一列标签,无特征可供继续划分又不满足所有标签相同)        return majorLabel(labelList)    # 就返回出现次数最多的标签作为叶子节点        bestFeatureIndex=chooseBestFeatureToSplit(dataSet)  # 获取当前样本集dataSet最优划分特征的索引    bestFeature=labels[bestFeatureIndex]                # 获取当前样本集dataSet的最优划分特征    decisionTree={bestFeature:{}}   # 字典存储决策树的信息    del(labels[bestFeatureIndex])   # 删除已经选出的特征    featureVals=[sample[bestFeatureIndex] for sample in dataSet] # 样本集中所有样本中的最优特征对应的特征值组成的列表(有重复值)    uniqueVals=set(featureVals)     # 最优特征对应的所有可能取值(无重复值)    for value in uniqueVals:        # 遍历最优特征所有可能的取值value        subLabels=labels[:]         # 将最优特征去除后的特征列表传递给subLabels        decisionTree[bestFeature][value]=createTree(splitDataSet(dataSet,bestFeatureIndex,value),subLabels)  # 递归生成decisionTree    return decisionTree     #? 对验证样本进行分类#  返回一个对样本分类后的标签classLabeldef classify(decisionTree,features,testSample):rootFeature=list(decisionTree.keys())[0]        # rootFeature:根节点是何种特征rootDict=decisionTree[rootFeature]              # rootDict为根节点的value值,是一个字典rootFeatureIndex=features.index(rootFeature)    # 获取根节点在特征列表中的索引for value in rootDict.keys():               # value为特征rootFeature的不同取值,并遍历valueif testSample[rootFeatureIndex]==value:     # 如果待测样本的该特征的特征值==valueif type(rootDict[value])==dict:     # 如果该特征值value对应的value'是一个字典classLabel=classify(rootDict[value],features,testSample)    # 则需要递归继续向决策树的下面结点查询else:   # 如果该特征值value对应的value'是一个单独的值(标签)classLabel=rootDict[value]      # 则该值就是要找的标签return classLabel   # 返回该样本testSample的标签if __name__=='__main__':    # 如果在当前模块/文件下执行,将会指定下述代码    dataSet, labels=createDataSet()    decisionTree=createTree(dataSet, labels)    print(f"\ndecisionTree={decisionTree}\n")     # 输出决策树模型结果    # 验证集    features=  ['色泽','根蒂','敲声','纹理','脐部','触感']  # 特征列表         testSample=['浅白','蜷缩','浊响','清晰','凹陷','硬滑']  # 待测样本    print(f"测试结果1sampleLabel= {classify(decisionTree,features,testSample)}\n")   # 输出测试结果    features=  ['色泽','根蒂','敲声','纹理','脐部','触感']  # 特征列表         testSample=['浅白','硬挺','清脆','模糊','平坦','硬滑']  # 待测样本    print(f"测试结果2sampleLabel= {classify(decisionTree,features,testSample)}\n")   # 输出测试结果    features=  ['色泽','根蒂','敲声','纹理','脐部','触感']  # 特征列表         testSample=['浅白','蜷缩','浊响','模糊','平坦','硬滑']  # 待测样本    print(f"测试结果3sampleLabel= {classify(decisionTree,features,testSample)}\n")   # 输出测试结果

来源地址:https://blog.csdn.net/weixin_66845445/article/details/130174519

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

ID3决策树及Python实现(详细)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python决策树算法怎么实现

这篇文章将为大家详细讲解有关python决策树算法怎么实现,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1、步骤计算数据集S中的每个属性的熵 H(xi)选取数据集S中熵值最小(或者信息增益最大,两者等价)
2023-06-15

怎么用Python实现CART决策树算法

这篇文章主要讲解了“怎么用Python实现CART决策树算法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么用Python实现CART决策树算法”吧!一、CART决策树算法简介CART(C
2023-06-25

python如何实现决策树分类算法

今天小编给大家分享一下python如何实现决策树分类算法的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。前置信息1、决策树决策
2023-07-02

怎么在Python中实现决策树算法

怎么在Python中实现决策树算法?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1.算法概述决策树算法是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大
2023-06-15

分析机器学习之决策树Python实现

目录一、环境准备二、决策树是什么三、快速入门分类树四、详细分析入门案例五、分类树参数解释5.1、criterion5.2、random_state & splitter5.3、剪枝参数5.4、目标权重参数:class_weight & mi
2022-06-02

Python实现决策树算法的原理与实现方式

决策树算法属于监督学习算法的范畴,适用于连续和分类输出变量,通常会被用于解决分类和回归问题。决策树是一种类似流程图的树结构,其中每个内部节点表示对属性的测试,每个分支表示测试的结果,每个节点都对应一个类标签。决策树算法思路开始,将整个
Python实现决策树算法的原理与实现方式
2024-01-22

详解B+树的原理及实现Python代码

B+树是自平衡树的高级形式,其中所有值都存在于叶级中。B+树所有叶子都处于同一水平,每个节点的子节点数量≥2。B+树与B树的区别是各节点在B树上不是相互连接,而在B+树上是相互连接的。B+树多级索引结构图B+树搜索规则1、从根节点开始
详解B+树的原理及实现Python代码
2024-01-24

Python基于决策树算法的分类预测怎么实现

今天小编给大家分享一下Python基于决策树算法的分类预测怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、决策树的
2023-06-26

详解B树删除操作:使用Python实现B树删除操作的详细图解

B树删除操作需要考虑节点所在位置和平衡,并且很有可能会发生下溢的情况。当一个节点包含的子节点数量少于它应该持有的最小数量时,就会发生下溢。图文展示B树删除操作原理在不影响平衡情况下。下溢情况。删除内部节点。Python实现B树删除
详解B树删除操作:使用Python实现B树删除操作的详细图解
2024-01-22

详解字典树Trie结构及其Python代码实现

字典树(Trie)可以保存一些字符串->值的对应关系。基本上,它跟 Java 的 HashMap 功能相同,都是 key-value 映射,只不过 Trie 的 key 只能是字符串。 Trie 的强大之处就在于它的时间复杂度。它的插入和查
2022-06-04

用Python实现堆栈中序遍历二叉树的详细步骤

使用堆栈无需递归就能遍历二叉树,下面是一个使用堆栈中序遍历二叉树的算法。算法思路1)创建一个空栈S。2)将当前节点初始化为root3)将当前节点推入S并设置current=current->left直到current为NULL4)
用Python实现堆栈中序遍历二叉树的详细步骤
2024-01-23

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录