合肥工业大学2021机器人技术作业四

第四次作业

题目:按照 ID3 算法推出最终的决策树。可程序实现;也可以手工推出(要有手动推出过程)
第四次作业
关于ID3算法:老师上课有简单介绍过,这里推荐大家去看这个分类算法——决策树ID3算法,容易理解与上手。

解题过程:
在上面的样本中,属于yes的结果有6个,no有6个,于是可以算出训练集的熵为:
E ( S ) = − 6 12 log ⁡ 2 6 12 − 6 12 log ⁡ 2 6 12 = 1.0 E(S)=-\frac{6}{12}\log_2\frac{6}{12}-\frac{6}{12}\log_2\frac{6}{12}=1.0 E(S)=126log2126126log2126=1.0
下面对各个属性计算对应的信息增益。

是否有其他选择yes/熵no/增益
24
42
0.91820.0818
饿否yes/熵no/增益
52
14
0.80420.1958
价格yes/熵no/增益
34
20
12
0.80420.1958
餐馆类型yes/熵no/增益
中式22
意大利式11
法式11
快餐22
1.00.0
顾客人数yes/熵no/增益
无人02
有人40
客满24
0.45910.5409
等待时间yes/熵no/增益
0-1042
10-3011
30-6011
>6002
0.79240.2076

从上面可以看出顾客人数的信息增益最大,所以选择顾客人数作为根节点的测试属性,餐馆类型的信息增益为0,不能做出任何分类信息,产生第一次决策树,然后对每个叶节点再次利用上面的过程,生成最终的决策树。

在这里插入图片描述
具体实现:
语言:Python 工具:PyCharm
源代码:(仅供参考,水平有限,有错请指出)

import math as m
def createDataSet():
    # choice:  0 no     1 yes
    # hungry:  0 no     1 yes
    # price:   0 low    1 mid     2 high
    # types:   0 china  1 italy   2 france   3 fast
    # peolpe:  0 nobody 1 some    2 full
    # waitmin: 0 0-10   1 10-30   2 30-60    3 >60
    dataSet = [[1, 1, 2, 2, 1, 0, 'yes'],
               [1, 1, 0, 0, 2, 2, 'no'],
               [0, 0, 0, 3, 1, 0, 'yes'],
               [1, 1, 0, 0, 2, 1, 'yes'],
               [1, 0, 2, 2, 2, 3, 'no'],
               [0, 1, 1, 1, 1, 0, 'yes'],
               [0, 0, 0, 3, 0, 0, 'no'],
               [0, 1, 1, 0, 1, 0, 'yes'],
               [0, 0, 0, 3, 2, 3, 'no'],
               [1, 1, 2, 1, 2, 1, 'no'],
               [1, 0, 0, 0, 0, 0, 'no'],
               [0, 1, 0, 3, 2, 2, 'yes'],
               ]
    return dataSet
# 计算数据集熵的函数
def calcShannonEnt(dataSet):
	numEntries = len(dataSet)	#获取数据的数目
	labelCounts = {}
	for featVec in dataSet:
		currentLable = featVec[-1] 	#取得最后一列数据,做为标签
		if currentLable not in labelCounts.keys(): 	#获取不同标签的数目
			labelCounts[currentLable] = 0 #初始化当前新增标签
		labelCounts[currentLable] += 1

	#计算熵
	Ent = 0.0
	for feat in labelCounts:
		prob = float(labelCounts[feat]) / numEntries
		Ent -= prob * m.log(prob, 2)
	#print ("信息熵: ", Ent)
	return Ent

# 按照给定特征划分数据集
def splitDataSet(dataSet, axis, value):
    # axis:给定特征 value:具体值--0、1、2
    retDataSet = []
    for featVec in dataSet:
        if featVec[axis] == value:  # 每行中第axis个元素和value相等(去除第axis个数据)
            reducedFeatVec = featVec[:axis]
            reducedFeatVec.extend(featVec[axis + 1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet  # 返回分类后的新矩阵

# 根据熵,选择最优的划分方式
# 根据某一属性划分后,类标签熵越低,效果越好
def chooseBestFeatureToSplit(dataSet):
    baseEntropy = calcShannonEnt(dataSet)  # 计算数据集的初始熵
    numFeatures = len(dataSet[0]) - 1 # 除结果外,其余都是特征
    bestInfoGain = 0.0  # 最大信息增益
    bestFeature = 0  # 最优特征
    for i in range(0, numFeatures):
        featList = [example[i] for example in dataSet]  # 所有子列表(每行)的第i个元素,组成一个新的列表
        # print(len(featList))
        # 将dataSet中的数据先按行依次放入example中,然后取得example中的example[i]元素,放入列表featList中
        # featList中是每种特征的详细数据
        uniqueVals = set(featList)
        newEntorpy = 0.0 # 新熵
        for value in uniqueVals:  # 数据集根据第i个属性进行划分,计算划分后数据集的熵
            subDataSet = splitDataSet(dataSet, i, value)
            prob = len(subDataSet) / float(len(dataSet))
            newEntorpy += prob * calcShannonEnt(subDataSet)
        infoGain = baseEntropy - newEntorpy  # 划分后的数据集,熵越小越好,即信息增益越大越好
        if (infoGain > bestInfoGain):# 信息增益最大
            bestInfoGain = infoGain# 确定最大增益
            bestFeature = i# 确定最好特征
    return bestFeature
# 训练算法
# 如果数据集已经处理了所有属性,但叶子结点中类标签依然不是唯一的,此时需要决定如何定义该叶子结点。这种情况下,采用多数表决方法,对该叶子结点进行分类
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)
    bestFeat = 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[:]
        subDataSet = splitDataSet(dataSet, bestFeat, value)
        myTree[bestFeatLabel][value] = createTree(subDataSet, subLabels)
    # print("myTree:", myTree)
    return myTree
# 测试
if __name__ == '__main__':
    dataSet = createDataSet()
    labels = ['choice', 'hungry', 'price', 'types', 'people', 'waitmin']
    labelsForCreateTree = labels[:]
    Tree = createTree(dataSet, labelsForCreateTree)
    print(Tree)
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值