基于Python实现ID3算法 演示视频
目录
一、作业任务
二、 运行环境
三、算法介绍
四、程序分析
制作数据集:
输出决策树结果
可视化决策树:
五、 界面截图与分析
1.通过图来大致观察一下不同属性的划分情况:
2.查看属性对于结果的划分影响:
3.程序运行控制台输出结果:
4.决策树可视化结果:
六、心得体会
七、参考资料
八、附录
代码
一、作业任务
1.编程实现ID3算法,针对下表数据,生成决策树。
问题提示:可设计数据文件格式,如color属性取值YELLOW:0,PURPLE:1等,程序从指定数据文件中读取训练集数据。
问题拓展:要求将计算各属性信息增益过程及决策树生成过程演示出来。
二、运行环境
编程语言:Python
使用第三方库:Numpy,Matplotlib,Scikit-learn
IDE:PyCharm
操作系统:WIndows10
决策树(decision tree)是一个树结构(可以是二叉树或非二叉树)。其每个非叶节点表示一个特征属性上的测试,每个分支代表这个特征属性在某个值域上的输出,而每个叶节点存放一个类别。使用决策树进行决策的过程就是从根节点开始,测试待分类项中相应的特征属性,并按照其值选择输出分支,直到到达叶子节点,将叶子节点存放的类别作为决策结果。引用《机器学习》(西瓜书)中的例子:
本文转载自:http://www.biyezuopin.vip/onews.asp?id=16531
from math import log
import operator # 此行加在文件顶部
import json
from utils.treeploter import *
# 计算信息熵
def calcShannonEnt(dataSet):
numEntries = len(dataSet) # 样本数
labelCounts = {}
for featVec in dataSet: # 遍历每个样本
currentLabel = featVec[-1] # 当前样本的类别
if currentLabel not in labelCounts.keys(): # 生成类别字典
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0
for key in labelCounts.keys(): # 计算信息熵
prob = float(labelCounts[key]) / numEntries
shannonEnt = shannonEnt - prob * log(prob, 2)
# print("属性%s 信息熵为%f"%(key,shannonEnt))
return shannonEnt
# 划分数据集,axis:按第几个属性划分,value:要返回的子集对应的属性值
def splitDataSet(dataSet, axis, value):
retDataSet = []
featVec = []
for featVec in dataSet:
if featVec[axis] == value:
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis + 1:])
retDataSet.append(reducedFeatVec)
return retDataSet
# 选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1 # 属性的个数
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0
bestFeature = -1
for i in range(numFeatures): # 对每个属性技术信息增益
featList = [example[i] for example in dataSet]
uniqueVals = set(featList) # 该属性的取值集合
newEntropy = 0.0
for value in uniqueVals: # 对每一种取值计算信息增益
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet) / float(len(dataSet))
newEntropy += prob * calcShannonEnt(subDataSet)
infoGain = baseEntropy - newEntropy
if (infoGain > bestInfoGain): # 选择信息增益最大的属性
bestInfoGain = infoGain
bestFeature = i
return bestFeature,bestInfoGain
# 通过排序返回出现次数最多的类别
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,bestGain = chooseBestFeatureToSplit(dataSet) # 最优划分属性的索引
bestFeatLabel = labels[bestFeat] # 最优划分属性的标签
print("当前最佳属性%s,信息熵%f" % (bestFeatLabel,bestGain))
myTree = {bestFeatLabel: {}}
del (labels[bestFeat]) # 已经选择的特征不再参与分类
featValues = [example[bestFeat] for example in dataSet]
uniqueValue = set(featValues) # 该属性所有可能取值,也就是节点的分支
for value in uniqueValue: # 对每个分支,递归构建树
subLabels = labels[:]
myTree[bestFeatLabel][value] = createTree(
splitDataSet(dataSet, bestFeat, value), subLabels)
return myTree
if __name__ == '__main__':
fr = open(r'data/text.txt')
listWm = [inst.strip().split(',')[1:] for inst in fr.readlines()[1:]]
# print(listWm)
fr.close()
fr = open(r'data/text.txt')
labels = fr.readlines()[0].split(',')[1:]
Trees = createTree(listWm, labels)
fr.close()
print(json.dumps(Trees, ensure_ascii=False))
createPlot(Trees)