机器学习——决策树实践(预测隐形眼镜类型)
前言
之前把《机器学习实战》这本书的分类部分学完了,想自己动手实践一下,所以从前面的章节开始,慢慢熟悉代码。
今天在学习决策树的时候,发现书中并没有直接给出预测隐形眼镜类型的代码,于是想借着这个机会自己实践一下。
在这过程中我使用原来的一些函数,比如创建决策树的函数,用来对官方给的文件进行分类,会出现
bestFeatLabel = labels[bestFeat]
IndexError: list index out of range
等错误,于是我就开始从头熟悉代码,print单步调试代码,最终得出了结果。
在原始代码上首先需要对文本数据进行编码
编码操作
编码操作是第一步,大家可以直接复制下面的代码看看结果。
我就直接上代码了,这也是我从博客中看到抄过来的
with open('lenses.txt', 'r') as fr: # 加载文件lenses = [inst.strip().split('\t') for inst in fr.readlines()] # 处理文件lenses_target = [] # 提取每组数据的类别,保存在列表里for each in lenses:lenses_target.append(each[-1])print(lenses)lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate','class'] # 特征标签lenses_list = [] # 保存lenses数据的临时列表lenses_dict = {} # 保存lenses数据的字典,用于生成pandasfor each_label in lensesLabels: # 提取信息,生成字典for each in lenses:lenses_list.append(each[lensesLabels.index(each_label)])lenses_dict[each_label] = lenses_listlenses_list = []print(lenses_dict) #打印字典信息lenses_pd = pd.DataFrame(lenses_dict) # 生成pandas.DataFrameprint(lenses_pd) # 打印pandas.DataFramele = LabelEncoder() # 创建LabelEncoder()对象,用于序列化for col in lenses_pd.columns: # 为每一列序列化lenses_pd[col] = le.fit_transform(lenses_pd[col])print(lenses_pd)
然后就可以使用创建决策树函数了。
代码
过程我也不多提了,直接上代码,想懂原理的请看我之前写的博客就好了。在这里,会出现我前言里面说过的错误,但通过单步调试,找出了问题所在,并解决了它。原因和解决方法我都写在了相应位置的注释,可以参考一下
# -*- coding: UTF-8 -*-
from math import log
from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt
import operator
import pickle
import pandas as pd
from sklearn.preprocessing import LabelEncoder
import pydotplus
import six"""
函数说明:计算给定数据集的经验熵(香农熵)
Parameters:dataSet - 数据集
Returns:shannonEnt - 经验熵(香农熵)
"""
def calcShannonEnt(dataSet):numEntires = len(dataSet) #返回数据集的行数,样本容量labelCounts = {} #保存每个标签(Label)出现次数的字典for featVec in dataSet: #对每组特征向量进行统计currentLabel = featVec[-1] #提取标签(Label)信息if currentLabel not in labelCounts.keys(): #如果标签(Label)没有放入统计次数的字典,添加进去labelCounts[currentLabel] = 0labelCounts[currentLabel] += 1 #Label计数shannonEnt = 0.0 #经验熵(香农熵)#print(labelCounts)for key in labelCounts: #计算香农熵#print(key)#print(labelCounts[key])prob = float(labelCounts[key]) / numEntires #选择该标签(Label)的概率shannonEnt -= prob * log(prob, 2) #利用公式计算return shannonEnt #返回经验熵(香农熵)"""
函数说明:创建测试数据集
Returns:dataSet - 数据集labels - 分类属性
"""
def createDataSet():dataSet = [[0, 0, 0, 0, 'no'], #数据集[0, 0, 0, 1, 'no'],[0, 1, 0, 1, 'yes'],[0, 1, 1, 0, 'yes'],[0, 0, 0, 0, 'no'],[1, 0, 0, 0, 'no'],[1, 0, 0, 1, 'no'],[1, 1, 1, 1, 'yes'],[1, 0, 1, 2, 'yes'],[1, 0, 1, 2, 'yes'],[2, 0, 1, 2, 'yes'],[2, 0, 1, 1, 'yes'],[2, 1, 0, 1, 'yes'],[2, 1, 0, 2, 'yes'],[2, 0, 0, 0, 'no']]labels = ['年龄', '有工作', '有自己的房子', '信贷情况'] #分类属性return dataSet, labels #返回数据集和分类属性"""
函数说明:按照给定特征划分数据集Parameters:dataSet - 待划分的数据集axis - 划分数据集的特征value - 需要返回的特征的值
"""
def splitDataSet(dataSet, axis, value):retDataSet = [] #创建返回的数据集列表for featVec in dataSet: #遍历数据集if featVec[axis] == value:reducedFeatVec = featVec[:axis] #去掉axis特征reducedFeatVec.extend(featVec[axis+1:]) #将符合条件的添加到返回的数据集retDataSet.append(reducedFeatVec)print("划分后的数据集:", retDataSet)return retDataSet #返回划分后的数据集"""
函数说明:选择最优特征
Parameters:dataSet - 数据集
Returns:bestFeature - 信息增益最大的(最优)特征的索引值
"""
def chooseBestFeatureToSplit(dataSet):numFeatures = len(dataSet[0]) - 1 #特征数量,-1是因为最后一列是类别标签#print("特征数量为:%d" % numFeatures)baseEntropy = calcShannonEnt(dataSet) #计算数据集的香农熵bestInfoGain = 0.0 #信息增益bestFeature = -1 #最优特征的索引值for i in range(numFeatures): #遍历所有特征#获取dataSet的第i个所有特征存到featList中featList = [example[i] for example in dataSet]#已用for验证,把dataSet中的每一行的第i个数据放到featList中#print(featList)#每个特征的15项特征值列表uniqueVals = set(featList) #创建set集合{},元素不可重复#print(uniqueVals)#去除重复项newEntropy = 0.0 #经验条件熵#把特征项的数据集分开,去除重复项的原因是将第i个特征的数据分离,对这个特征的进行经验熵的计算for value in uniqueVals: #计算信息增益subDataSet = splitDataSet(dataSet, i, value) #subDataSet划分后的子集#print(subDataSet)prob = len(subDataSet) / float(len(dataSet)) #计算子集的概率=子集个数除以整个训练集样本个数newEntropy += prob * calcShannonEnt(subDataSet) #根据公式计算经验条件熵infoGain = baseEntropy - newEntropy #信息增益#print("第%d个特征的增益为%.3f" % (i, infoGain)) #打印每个特征的信息增益if (infoGain > bestInfoGain): #计算信息增益bestInfoGain = infoGain #更新信息增益,找到最大的信息增益bestFeature = i #记录信息增益最大的特征的索引值return bestFeature #返回信息增益最大的特征的索引值"""
函数说明:创建决策树
Parameters:dataSet - 训练数据集labels - 分类属性标签featLabels - 存储选择的最优特征标签
Returns:myTree - 决策树
"""
def createTree2(dataSet, labels, featLabels):classList = [example[-1] for example in dataSet] #取分类标签(是否放贷:yes or no)#print(len(dataSet[0]))if classList.count(classList[0]) == len(classList): #如果类别完全相同则停止继续划分return classList[0]if len(dataSet[0]) == 1: #遍历完所有特征时返回出现次数最多的类标签return majorityCnt(classList)bestFeat = chooseBestFeatureToSplit(dataSet) #选择最优特征bestFeatLabel = labels[bestFeat] #最优特征的标签featLabels.append(bestFeatLabel)myTree = {bestFeatLabel:{}} #根据最优特征的标签生成树del(labels[bestFeat]) #删除已经使用特征标签featValues = [example[bestFeat] for example in dataSet] #得到训练集中所有最优特征的属性值uniqueVals = set(featValues) #去掉重复的属性值for value in uniqueVals: #遍历特征,创建决策树。myTree[bestFeatLabel][value] = createTree2(splitDataSet(dataSet, bestFeat, value), labels, featLabels)return myTree"""
函数说明:统计classList中出现此处最多的元素(类标签)
Parameters:classList - 类标签列表
Returns:sortedClassCount[0][0] - 出现此处最多的元素(类标签)
"""
def majorityCnt(classList):classCount = {}for vote in classList: #统计classList中每个元素出现的次数if vote not in classCount.keys():classCount[vote] = 0classCount[vote] += 1sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True) #根据字典的值降序排序return sortedClassCount[0][0] #返回classList中出现次数最多的元素"""
函数说明:创建决策树
Parameters:dataSet - 训练数据集labels - 分类属性标签featLabels - 存储选择的最优特征标签
Returns:myTree - 决策树
"""
def createTree(dataSet, labels, featLabels):print("****************************************************")print("数据集为:", dataSet)classList = [example[-1] for example in dataSet] #取分类标签(是否放贷:yes or no)"""特征可能存在多个属性,所以在此判断一下,如果类别完全相同则停止继续划分"""if classList.count(0) == len(classList): #如果类别完全相同则停止继续划分print("停止划分0")return 0elif classList.count(1) == len(classList):print("停止划分1")return 1elif classList.count(2) == len(classList):print("停止划分2")return 2if len(dataSet[0]) == 1: #遍历完所有特征时返回出现次数最多的类标签return majorityCnt(classList)bestFeat = chooseBestFeatureToSplit(dataSet) #选择最优特征print("最优特征为:%d" % bestFeat)bestFeatLabel = labels[bestFeat] #最优特征的标签print("最优特征的标签:", bestFeatLabel)featLabels.append(bestFeatLabel)myTree = {bestFeatLabel:{}} #根据最优特征的标签生成树print("当前根据最优特征生成的树:", myTree)print("准备删除的特征标签为:", labels[bestFeat])#如果是到了三个属性的特征值里,那么不能让他就这么把前面没有创建完的特征标签删除了,因为他是从一个属性递归到底再回到另一个属性进行递归del (labels[bestFeat]) # 删除已经使用特征标签'age', 'prescript', 'astigmatic', 'tearRate'print("labels标签里还有:", labels)featValues = [example[bestFeat] for example in dataSet] #得到训练集中所有最优特征的属性值print("得到训练集中最优特征的属性值:", featValues)uniqueVals = set(featValues) #去掉重复的属性值print("去掉重复属性:", uniqueVals)for value in uniqueVals: #0/1/2 遍历特征,创建决策树。if len(uniqueVals) == 3:print("***************************************************************************************三个属性的第", value)subLabels = labels[:]"""我在没有加subLabels = labels[:]的时候,会报如下错误: bestFeatLabel = labels[bestFeat] #最优特征的标签IndexError: list index out of range经过单步调试与print结果,才发现:当我输入数据中的特征存在不止2个属性的时候,在递归内每次都会删除已经使用的标签,这就可能存在删除一个还没有全部迭代完的属性(比如只迭代了0属性到树底,回过头来迭代1属性时,发现已经在迭代到树底过程中就被删除了)所以为了防止误删除,我们需要在迭代一个属性时复制所有标签,这样树就不会弄乱现有的标签"""myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels, featLabels)print("当前树:", myTree)return myTree"""
函数说明:获取决策树叶子结点的数目
Parameters:myTree - 决策树
Returns:numLeafs - 决策树的叶子结点的数目
"""
def getNumLeafs(myTree):numLeafs = 0 #初始化叶子firstStr = next(iter(myTree)) #python3中myTree.keys()返回的是dict_keys,不在是list,所以不能使用myTree.keys()[0]的方法获取结点属性,可以使用list(myTree.keys())[0]secondDict = myTree[firstStr] #获取下一组字典for key in secondDict.keys():if type(secondDict[key]).__name__=='dict': #测试该结点是否为字典,如果不是字典,代表此结点为叶子结点numLeafs += getNumLeafs(secondDict[key])else: numLeafs +=1return numLeafs"""
函数说明:获取决策树的层数
Parameters:myTree - 决策树
Returns:maxDepth - 决策树的层数
"""
def getTreeDepth(myTree):maxDepth = 0 #初始化决策树深度firstStr = next(iter(myTree)) #python3中myTree.keys()返回的是dict_keys,不在是list,所以不能使用myTree.keys()[0]的方法获取结点属性,可以使用list(myTree.keys())[0]secondDict = myTree[firstStr] #获取下一个字典for key in secondDict.keys():if type(secondDict[key]).__name__=='dict': #测试该结点是否为字典,如果不是字典,代表此结点为叶子结点thisDepth = 1 + getTreeDepth(secondDict[key])else: thisDepth = 1if thisDepth > maxDepth: maxDepth = thisDepth #更新层数return maxDepth"""
函数说明:绘制结点
Parameters:nodeTxt - 结点名centerPt - 文本位置parentPt - 标注的箭头位置nodeType - 结点格式
"""
def plotNode(nodeTxt, centerPt, parentPt, nodeType):arrow_args = dict(arrowstyle="<-") #定义箭头格式font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14) #设置中文字体createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction', #绘制结点xytext=centerPt, textcoords='axes fraction',va="center", ha="center", bbox=nodeType, arrowprops=arrow_args, FontProperties=font)"""
函数说明:标注有向边属性值
Parameters:cntrPt、parentPt - 用于计算标注位置txtString - 标注的内容
"""
def plotMidText(cntrPt, parentPt, txtString):xMid = (parentPt[0]-cntrPt[0])/2.0 + cntrPt[0] #计算标注位置yMid = (parentPt[1]-cntrPt[1])/2.0 + cntrPt[1]createPlot.ax1.text(xMid, yMid, txtString, va="center", ha="center", rotation=30)"""
函数说明:绘制决策树
Parameters:myTree - 决策树(字典)parentPt - 标注的内容nodeTxt - 结点名
"""
def plotTree(myTree, parentPt, nodeTxt):decisionNode = dict(boxstyle="sawtooth", fc="0.8") #设置结点格式leafNode = dict(boxstyle="round4", fc="0.8") #设置叶结点格式numLeafs = getNumLeafs(myTree) #获取决策树叶结点数目,决定了树的宽度depth = getTreeDepth(myTree) #获取决策树层数firstStr = next(iter(myTree)) #下个字典cntrPt = (plotTree.xOff + (1.0 + float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff) #中心位置plotMidText(cntrPt, parentPt, nodeTxt) #标注有向边属性值plotNode(firstStr, cntrPt, parentPt, decisionNode) #绘制结点secondDict = myTree[firstStr] #下一个字典,也就是继续绘制子结点plotTree.yOff = plotTree.yOff - 1.0/plotTree.totalD #y偏移for key in secondDict.keys():if type(secondDict[key]).__name__=='dict': #测试该结点是否为字典,如果不是字典,代表此结点为叶子结点plotTree(secondDict[key],cntrPt,str(key)) #不是叶结点,递归调用继续绘制else: #如果是叶结点,绘制叶结点,并标注有向边属性值plotTree.xOff = plotTree.xOff + 1.0/plotTree.totalWplotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))plotTree.yOff = plotTree.yOff + 1.0/plotTree.totalD"""
函数说明:创建绘制面板
Parameters:inTree - 决策树(字典)
"""
def createPlot(inTree):fig = plt.figure(1, facecolor='white') #创建figfig.clf() #清空figaxprops = dict(xticks=[], yticks=[])createPlot.ax1 = plt.subplot(111, frameon=False, **axprops) #去掉x、y轴plotTree.totalW = float(getNumLeafs(inTree)) #获取决策树叶结点数目plotTree.totalD = float(getTreeDepth(inTree)) #获取决策树层数plotTree.xOff = -0.5/plotTree.totalW; plotTree.yOff = 1.0; #x偏移plotTree(inTree, (0.5,1.0), '') #绘制决策树plt.show() #显示绘制结果"""
函数说明:使用决策树分类
Parameters:inputTree - 已经生成的决策树featLabels - 存储选择的最优特征标签testVec - 测试数据列表,顺序对应最优特征标签
Returns:classLabel - 分类结果
"""def classify(inputTree, featLabels, testVec):firstStr = next(iter(inputTree)) #获取决策树结点print("获取决策树结点:",firstStr)secondDict = inputTree[firstStr] #下一个字典print("下一个字典:",secondDict)featIndex = featLabels.index(firstStr)#获取存储选择的最优特征标签的索引print("获取存储选择的最优特征标签的索引:",featIndex)for key in secondDict.keys():#遍历字典的键print("字典的键:",key)if testVec[featIndex] == key:if type(secondDict[key]).__name__ == 'dict':classLabel = classify(secondDict[key], featLabels, testVec)else: classLabel = secondDict[key]return classLabel"""
函数说明:存储决策树
Parameters:inputTree - 已经生成的决策树filename - 决策树的存储文件名
"""
def storeTree(inputTree, filename):with open(filename, 'wb') as fw:pickle.dump(inputTree, fw)"""
函数说明:读取决策树
Parameters:filename - 决策树的存储文件名
Returns:pickle.load(fr) - 决策树字典
"""
def grabTree(filename):fr = open(filename, 'rb')return pickle.load(fr)if __name__ == '__main__':"""计算香农熵、条件经验熵、信息增益、选择最优特征dataSet, labels = createDataSet()print("最优特征索引值:" + str(chooseBestFeatureToSplit(dataSet)))""""""dataSet, labels = createDataSet()print(dataSet)featLabels = []myTree = createTree2(dataSet, labels, featLabels)print(myTree)""""""可视化决策树dataSet, labels = createDataSet()featLabels = []myTree = createTree(dataSet, labels, featLabels)print(myTree)createPlot(myTree)""""""决策树进行分类dataSet, labels = createDataSet()featLabels = []myTree = createTree(dataSet, labels, featLabels)testVec = [0, 1] # 测试数据result = classify(myTree, featLabels, testVec)if result == 'yes':print('放贷')if result == 'no':print('不放贷')""""""进行编码"""with open('lenses.txt', 'r') as fr: # 加载文件lenses = [inst.strip().split('\t') for inst in fr.readlines()] # 处理文件lenses_target = [] # 提取每组数据的类别,保存在列表里for each in lenses:lenses_target.append(each[-1])print(lenses)lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate','class'] # 特征标签lenses_list = [] # 保存lenses数据的临时列表lenses_dict = {} # 保存lenses数据的字典,用于生成pandasfor each_label in lensesLabels: # 提取信息,生成字典for each in lenses:lenses_list.append(each[lensesLabels.index(each_label)])lenses_dict[each_label] = lenses_listlenses_list = []print(lenses_dict) #打印字典信息lenses_pd = pd.DataFrame(lenses_dict) # 生成pandas.DataFrameprint(lenses_pd) # 打印pandas.DataFramele = LabelEncoder() # 创建LabelEncoder()对象,用于序列化for col in lenses_pd.columns: # 为每一列序列化lenses_pd[col] = le.fit_transform(lenses_pd[col])print(lenses_pd)featLabels = []lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate'] # 特征标签myTree = createTree(lenses_pd.values.tolist(), lensesLabels, featLabels)print("树结构:",myTree)print("存储选择的最优特征标签:",featLabels)testVec = [1,1,1,0] # 测试数据lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate'] # 特征标签"""这里我给的参数是lensesLabels所以测试数据他是按照你的特征标签给的标准来进行分类的如果参数给的是featLabels那么测试数据他是按照你的树结构来给值才会成功分类"""result = classify(myTree, lensesLabels, testVec)if result == 0 :print("类型为:hard ")elif result == 1:print("类型为:no lenses ")elif result == 2:print("类型为:soft ")createPlot(myTree)
这就是全部的代码,中间有许多打印的东西还有许多注释我没有删,主要是懒,看结果就好了,可以通过修改测试数据来得到不同的分类结果。
机器学习——决策树实践(预测隐形眼镜类型)相关推荐
- 机器学习之决策树实践:隐形眼镜类型预测
步骤: 收集数据:使用书中提供的小型数据集 准备数据:对文本中的数据进行预处理,如解析数据行 分析数据:快速检查数据,并使用createPlot()函数绘制最终的树形图 训练决策树:使用createT ...
- 机器学习实战--决策树ID3的构建、画图与实例:预测隐形眼镜类型
声明 本文参考了<机器学习实战>书中代码,结合该书讲解,并加之自己的理解和阐述 机器学习实战系列博文 机器学习实战--k近邻算法改进约会网站的配对效果 机器学习实战--决策树的构建.画图与 ...
- 【python和机器学习入门2】决策树3——使用决策树预测隐形眼镜类型
参考博客:决策树实战篇之为自己配个隐形眼镜 (po主Jack-Cui,<--大部分内容转载自 参考书籍:<机器学习实战>--第三章3.4 <--决策树基础知识见前两篇 , 摘要 ...
- 徒手写代码之《机器学习实战》-----决策树算法(2)(使用决策树预测隐形眼镜类型)
使用决策树预测隐形眼镜类型 说明: 将数据集文件 'lenses.txt' 放在当前文件夹 from math import log import operator 熵的定义 "" ...
- 机器学习实战之决策树(四)示例:预测隐形眼镜类型(含数据集)
决策树(四)示例:预测隐形眼镜类型 流程 代码 决策树小结 转载请注明作者和出处:https://blog.csdn.net/weixin_45814668 微信公众号:qiongjian0427 知 ...
- 《机器学习实战》学习笔记:绘制树形图使用决策树预测隐形眼镜类型
上一节实现了决策树,但只是使用包含树结构信息的嵌套字典来实现,其表示形式较难理解,显然,绘制直观的二叉树图是十分必要的.Python没有提供自带的绘制树工具,需要自己编写函数,结合Matplotlib ...
- Python3:《机器学习实战》之决策树算法(3)预测隐形眼镜类型
Python3:<机器学习实战>之决策树算法(3)预测隐形眼镜类型 转载请注明作者和出处:http://blog.csdn.net/u011475210 代码地址:https://gith ...
- Python3:《机器学习实战》之决策算法(3)预测隐形眼镜类型
Python3:<机器学习实战>之决策树算法(3)预测隐形眼镜类型 转载请注明作者和出处:http://blog.csdn.net/u011475210 代码地址:https://gith ...
- 03_使用决策树预测隐形眼镜类型
使用决策树预测隐形眼镜类型 1.实验描述 使用Python编程,输入为隐形眼镜数据集,计算所有可能的特征的信息增益,选择最优的特征值划分数据集,进而递归地构建决策树.其中为了更加直观地呈现决策树,使用 ...
最新文章
- linux里进程监控和自动重启,Linux - linux进程监控和自动重启的简单实现
- xss跨站脚本,纯安全测试干货分享-建议收藏
- easyui 1.4.2 Tab刷新图标重复问题
- 计算机专业技能考核方案,计算机专业技能课教学目标考核方案教程.doc
- tesseract 样例
- C语言基础专题 - 存储类(编辑中)
- Linux将文件复制粘贴到另外一个位置
- 算法学习笔记:连通图详解
- 什么是SQL脚本?及作用和命令
- Threejs3D模型爆炸效果
- 公农历互转js库-solarlunar-es
- notebook常用快捷键
- Android baidu地图定位实现签到打卡功能(附源码)
- 高性能分布式执行框架——Ray
- 卫星影像免费下载地址
- 6-25漏洞利用-irc后门利用
- css3两种hover动画
- 使用 T-SQL 语句完成数据综合检索
- 知识图谱入门 【九】- 知识问答
- 详解TCP之listen
热门文章
- 电子仪表系统显示管理计算机,综合电子仪表系统公开课.ppt
- 传图识字显示服务器开小差,传图识字小程序
- C++学xuexi (6)转换函数
- 【PPT】水墨画彩56套模板
- html5三国策略布阵,高比例修改版三国策略页游SF《兵法三国SF》新玩法,兵法三国布阵系统怎么玩?...
- android 系统 锁屏界面,在安卓手机系统使用Ubuntu漂亮的锁屏界面攻略
- H5实现聚合支付及踩坑
- 邮箱如何批量购买?邮箱购买推荐,买邮箱哪个比较便宜呢?
- beta阶段第八次scrum meeting
- NVIDIA GTC主题演讲内容学习<6-end>