机器学习--决策树理解
来源:互联网 发布:php ajax提交form表单 编辑:程序博客网 时间:2024/05/21 17:41
怕什么真理无穷,进一寸有一寸的欢喜。
工具:
python3.x
anaconda
代码均在Spyder
测试均在IPython
简单思路:
第一步:做出选择,第二步:生成结果,第三步:实例化
栗子
圣诞节快到了,你想要约心仪对象看电影,待挑选的影片种类有:喜剧、恐怖、文艺、科幻,你想挑选个她喜欢的电影类型,那么该如何挑选呢?
根据如下数据集
你可以根据她的爱好,性格,喜欢电影的国家,和当天的天气,投其所好!
由决策树算法,根据得到的结果(如下),可以合理的挑选影片
开始有趣的决策树:
具体思路:
一、如何决策?
1.1 如何决策?
通过划分数据集,实现决策的目的
也就是说,对例子中数据集进行分析,最终达到可以根据女孩儿的爱好,性格,喜欢电影的国家,和圣诞节当天的天气,知道女孩儿喜欢的电影类型
1.2 如何划分数据集?
通过给定的特征来划分数据集
例如本例子中,给定的特征即:爱好,性格,喜欢电影的国家,和天气
1.3 哪些特征才是最好的选择?
获得信息增益最高的特征就是最好的选择
最好的选择即树的根节点
1.4 信息增益怎么理解,如何计算?
信息增益是 划分数据集前后 信息发生的变化
信息增益越大说明该选择越好,也就是说最具有决策性
2 代码来了
2.1 计算信息熵
#计算香农熵def calcShannonEnt(dataSet):#dataset:数据集 numEntries = len(dataSet)#返回数据集行数 labelCounts = {}#类型:字典;功能:返回每个标签label出现的次数 for featVec in dataSet: currentLabel = featVec[-1]#提取最后一列,即标签label if currentLabel not in labelCounts.keys(): #如果标签(Label)没有放入统计次数的字典,添加进去 labelCounts[currentLabel] = 0#初始化 labelCounts[currentLabel] += 1#对标签label计数 shannonEnt = 0.0#香农熵,初始化 #计算香农熵 for key in labelCounts: prob = float(labelCounts[key])/numEntries#选择该标签的概率 shannonEnt -= prob * log(prob,2) #根据公式计算 return shannonEnt#返回香农熵
香浓熵公式:
对字典键值的理解:
对字典键值keys的理解
#导入数据fr =open('test.txt')dataset=[inst.strip().split('\t') for inst in fr.readlines()]#转化为列表#性格 爱好 地区 天气 类别labels=['性格','爱好','地区','天气']#标签
测试:
import trees#导入源文件cal=trees.calcShannonEnt(dataset)#调用函数cal#输出香农熵结果Out[8]: 1.7822287189138017
2.2 根据特征划分数据集
#根据特征划分数据集#dataset:数据集,axis:划分数据集的特征(也就是列),value: 需要返回的特征的值def splitDataSet(dataSet, axis, value): retDataSet = []#创建返回数据集的列表 for featVec in dataSet: if featVec[axis] == value: reducedFeatVec = featVec[:axis]#取出用于划分的特征列 reducedFeatVec.extend(featVec[axis+1:])#将符合条件的添加到返回的数据集,形如:['','','',...] retDataSet.append(reducedFeatVec)#将符合条件的返回到列表中,形如:[[ ],[ ],[ ]...] return retDataSet
测试:
import treesdatasetOut[11]: [['内向', '看书', '中国', '晴', '文艺'], ['外向', '跑步', '美国', '阴', '科幻'], ['内向', '看书', '日本', '阴', '文艺'], ['内向', '看书', '日本', '阴', '文艺'], ['内向', '跑步', '中国', '晴', '恐怖'], ['外向', '跑步', '中国', '阴', '喜剧'], ['外向', '看书', '中国', '晴', '文艺'], ['内向', '看书', '日本', '晴', '文艺'], ['外向', '看书', '中国', '阴', '喜剧'], ['外向', '跑步', '美国', '阴', '科幻'], ['外向', '看书', '中国', '晴', '文艺'], ['外向', '跑步', '美国', '晴', '喜剧'], ['外向', '看书', '中国', '晴', '文艺'], ['外向', '跑步', '中国', '阴', '喜剧'], ['外向', '看书', '中国', '晴', '文艺'], ['内向', '跑步', '美国', '阴', '喜剧'], ['外向', '看书', '中国', '晴', '文艺'], ['内向', '跑步', '美国', '阴', '喜剧'], ['内向', '跑步', '日本', '阴', '恐怖'], ['外向', '跑步', '美国', '阴', '科幻']]trees.splitDataSet(dataset,0,'内向')#选取:第0列 值为‘内向’的列表#由输出可以看出,用于选择的特征列被抽取Out[12]: [['看书', '中国', '晴', '文艺'], ['看书', '日本', '阴', '文艺'], ['看书', '日本', '阴', '文艺'], ['跑步', '中国', '晴', '恐怖'], ['看书', '日本', '晴', '文艺'], ['跑步', '美国', '阴', '喜剧'], ['跑步', '美国', '阴', '喜剧'], ['跑步', '日本', '阴', '恐怖']]trees.splitDataSet(dataset,2,'中国')Out[13]: [['内向', '看书', '晴', '文艺'], ['内向', '跑步', '晴', '恐怖'], ['外向', '跑步', '阴', '喜剧'], ['外向', '看书', '晴', '文艺'], ['外向', '看书', '阴', '喜剧'], ['外向', '看书', '晴', '文艺'], ['外向', '看书', '晴', '文艺'], ['外向', '跑步', '阴', '喜剧'], ['外向', '看书', '晴', '文艺'], ['外向', '看书', '晴', '文艺']]
2.3 找到最佳划分特征
def chooseBestFeatureToSplit(dataSet): numFeatures = len(dataSet[0]) - 1 #特征数量,-1:减去标签label列 #print(numFeatures) #测试:输出为4 baseEntropy = calcShannonEnt(dataSet) #计算数据集的香农熵 bestInfoGain = 0.0 #信息增益,初始化 bestFeature = -1 #最优特征的索引值,初始化(可以不等于-1,特征列从0开始,所以等于-1) for i in range(numFeatures): #遍历所有的特征 featList = [example[i] for example in dataSet] #获取数据集dataSet的第i个所有特征 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 #返回最佳信息增益特征的索引值
测试:
分别采用非数据集及数据集形式
非数据集:
test=[[1, 1, 0, 1, 1],[1, 1, 0, 1, 1],[1, 1, 0, 1, 1]]for i in range(2): featList = [example[i] for example in test]featListOut[36]: [1, 1, 1]uniqueVals = set(featList)uniqueValsOut[38]: {1}
数据集:
在原函数中增加了两个输出
for i in range(numFeatures): featList = [example[i] for example in dataSet] print(featList) uniqueVals = set(featList) print(uniqueVals) newEntropy = 0.0
查看结果
import treestrees.chooseBestFeatureToSplit(dataset)['内向', '外向', '内向', '内向', '内向', '外向', '外向', '内向', '外向', '外向', '外向', '外向', '外向', '外向', '外向', '内向', '外向', '内向', '内向', '外向']{'内向', '外向'}['看书', '跑步', '看书', '看书', '跑步', '跑步', '看书', '看书', '看书', '跑步', '看书', '跑步', '看书', '跑步', '看书', '跑步', '看书', '跑步', '跑步', '跑步']{'跑步', '看书'}['中国', '美国', '日本', '日本', '中国', '中国', '中国', '日本', '中国', '美国', '中国', '美国', '中国', '中国', '中国', '美国', '中国', '美国', '日本', '美国']{'日本', '中国', '美国'}['晴', '阴', '阴', '阴', '晴', '阴', '晴', '晴', '阴', '阴', '晴', '晴', '晴', '阴', '晴', '阴', '晴', '阴', '阴', '阴']{'晴', '阴'}Out[46]: 1
Out[46]: 1
说明:第1个特征是最好的用于划分数据集的特征,即‘爱好’列,通过最后的树结构以及可视化结果,也可以看出‘爱好’列为最佳化分列
二、怎么生成树?
2.1 怎么生成树?
通过递归构建决策树
#找出叶子节点def majorityCnt(classList): classCount = {} #统计classList中每个元素出现的次数 for vote in classList: if vote not in classCount.keys(): classCount[vote] = 0 classCount[vote] += 1 sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True) #用sorted函数对字典的值降序(reverse=True)排序 return sortedClassCount[0][0] #返回classList中出现次数最多的元素#创建决策树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] #最优特征的标签 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] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels) return myTree
测试:
import treestrees.createTree(dataset,labels)Out[49]: {'爱好': {'看书': {'天气': {'晴': '文艺', '阴': {'性格': {'内向': '文艺', '外向': '喜剧'}}}}, '跑步': {'地区': {'中国': {'性格': {'内向': '恐怖', '外向': '喜剧'}}, '日本': '恐怖', '美国': {'性格': {'内向': '喜剧', '外向': {'天气': {'晴': '喜剧', '阴': '科幻'}}}}}}}}
三、实例化
import matplotlib.pyplot as pltdecisionNode = dict(boxstyle="sawtooth", fc="0.8")leafNode = dict(boxstyle="round4", fc="0.8")arrow_args = dict(arrowstyle="<-")def getNumLeafs(myTree): numLeafs = 0 firstStr = list(myTree.keys())[0] secondDict = myTree[firstStr] for key in secondDict.keys(): if type(secondDict[key]).__name__=='dict':#test to see if the nodes are dictonaires, if not they are leaf nodes numLeafs += getNumLeafs(secondDict[key]) else: numLeafs +=1 return numLeafsdef getTreeDepth(myTree): maxDepth = 0 firstStr = list(myTree.keys())[0] secondDict = myTree[firstStr] for key in secondDict.keys(): if type(secondDict[key]).__name__=='dict':#test to see if the nodes are dictonaires, if not they are leaf nodes thisDepth = 1 + getTreeDepth(secondDict[key]) else: thisDepth = 1 if thisDepth > maxDepth: maxDepth = thisDepth return maxDepthdef plotNode(nodeTxt, centerPt, parentPt, nodeType): createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction', xytext=centerPt, textcoords='axes fraction', va="center", ha="center", bbox=nodeType, arrowprops=arrow_args )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)def plotTree(myTree, parentPt, nodeTxt):#if the first key tells you what feat was split on numLeafs = getNumLeafs(myTree) #this determines the x width of this tree depth = getTreeDepth(myTree) firstStr = list(myTree.keys())[0] #the text label for this node should be this 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 for key in secondDict.keys(): if type(secondDict[key]).__name__=='dict':#test to see if the nodes are dictonaires, if not they are leaf nodes plotTree(secondDict[key],cntrPt,str(key)) #recursion else: #it's a leaf node print the leaf node plotTree.xOff = plotTree.xOff + 1.0/plotTree.totalW plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode) plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key)) plotTree.yOff = plotTree.yOff + 1.0/plotTree.totalD#if you do get a dictonary you know it's a tree, and the first element will be another dictdef createPlot(inTree): fig = plt.figure(1, facecolor='white') fig.clf() axprops = dict(xticks=[], yticks=[]) createPlot.ax1 = plt.subplot(111, frameon=False, **axprops) plotTree.totalW = float(getNumLeafs(inTree)) plotTree.totalD = float(getTreeDepth(inTree)) plotTree.xOff = -0.5/plotTree.totalW; plotTree.yOff = 1.0; plotTree(inTree, (0.5,1.0), '') plt.savefig('movie.png') plt.show()
四、 参考
以上均参考《机器学习实战》
- 机器学习--决策树理解
- 机器学习-决策树(理解+代码)
- 机器学习之决策树模型组合理解
- 机器学习实战python版第三章决策树代码理解
- 机器学习实战-第三章决策树-代码理解-读书笔记
- 机器学习算法:决策树、聚类算法和回归理解
- 机器学习算法---决策树
- 机器学习2决策树
- 机器学习-决策树
- 机器学习---决策树
- 机器学习实战---决策树
- 机器学习之决策树
- 机器学习-决策树
- 机器学习实战-决策树
- 面试:机器学习--决策树
- 机器学习实战---决策树
- 机器学习实战 决策树
- 【机器学习】决策树
- java调用C# WebService接口
- Java把一个大的文本文件拆分成几个小的文件
- 【mysql 触发器】触发器使用
- enums中Enum对象取值
- 面向对象编程-鸵鸟到底是不是鸟?企鹅是不是鸟?
- 机器学习--决策树理解
- MySQL常用指令整理
- mac下ppt打开后没有显示怎么办
- 代码传奇 | 身价10亿的程序员 雷军当年也为他打工——WPS之父 求伯君
- python 画风矢量图
- 在20岁到30岁的约定
- java习题-(七)
- in查询优化
- Aras innovator: 粗绘innovator框架