决策树(Decision Tree)主要是用来处理分类问题,是最经常使用的数据挖掘算法之一。
决策树须知概念
熵指的是体系的混乱程度
信息熵(香农熵)是一种信息的度量方式,表示信息的混乱程度,信息越有序,熵越低。
信息增益:在划分数据集前后信息发生的变化称为信息增益
决策树工作原理:
决策树算法特点:
优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。
缺点:可能会产生过度匹配问题。
适用数据类型:数值型和标称型。
'''
Created on 2019/6/6
Author: ZJ
'''
print(__doc__)
import operator
import decisionTreePlot as dtPlot
from math import log
#根据给定的数据集计算香农熵
def calcshannonEnt(dataSet):
numEntries = len(dataSet)
#统计每个标签出现的次数 使用字典保存
labelCount = {}
for i in dataSet:
labelCount[i[-1]] = labelCount.get(i[-1],0) + 1
#计算香农熵,香农熵越小越好
shannonEnt = 0
for key in labelCount:
prob = float(labelCount[key]/numEntries)
shannonEnt -= prob * log(prob,2)
return shannonEnt
#划分数据集
def splitDataSet(dataSet,index,value):
#就是依据index列进行分类,如果index列的数据等于 value的时候,就要将 index 划分到我们创建的新的数据集中
retDataSet = []
for feature in dataSet:
temp = []
if feature[index] == value:
temp.extend(feature[:index])
temp.extend(feature[index+1:])
retDataSet.append(temp)
return retDataSet
#选择最好的数据集划分方式,选择最好的特征,返回切割数据集最好的特征的列bestFeature
def chooseBestFeatureToSplit(dataSet):
#特征的数目
featurenum = len(dataSet[0]) - 1
#label的原始香农熵
baseEntropy = calcshannonEnt(dataSet)
#最优的特征列数
bestFeature = -1
#最优的信息增益
bestInfoGain = 0.0
for index in range(featurenum):
featlist = [x[index] for x in dataSet]
#将该特征的选项去重放到集合中
uniqueVals = set(featlist)
#临时信息熵
newEntropy = 0.0
for value in uniqueVals :
#子数据集
subDataSet = splitDataSet(dataSet,index,value)
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob*calcshannonEnt(subDataSet)
#信息增益是熵的减少或者是数据无序度的减少。最后,比较所有特征中的信息增益,返回最好特征划分的索引值。
infoGain = newEntropy - baseEntropy
if bestInfoGain > infoGain:
bestInfoGain = infoGain
bestFeature = index
return bestFeature
#选择出现次数最多的结果
def majorlabel(classList):
majorCount = {}
for i in classList:
majorCount[i] = majorCount.get(i,0) + 1
sortdeMajorCount = sorted(majorCount.items(),key = operator.itemgetter(1),reverser = True)
return sortdeMajorCount[0][0]
#构建树的数据结构,返回构建好的决策树
def creatTree(dataSet,Labels):
classList = [x[-1] for x in dataSet]
if classList.count(classList[0]) == len(classList):
return classList[0]
#用完了所有的特征仍然不能正常分类,那么就选label出现次数最多的标签
if len(dataSet[0]) == 1:
return majorlabel(classList)
#得到最好的特征列
bestFeature = chooseBestFeatureToSplit(dataSet)
#该特征列的label名称
bestLabel = Labels[bestFeature]
#删除该名称从Labels中
del Labels[bestFeature]
myTree = {bestLabel:{}}
#取出特征列,构建选项集合
featValues = [x[bestFeature] for x in dataSet]
uniqueVals = set(featValues)
for i in uniqueVals:
subLabels = Labels[:]
myTree[bestLabel][i] = creatTree(splitDataSet(dataSet,bestFeature,i),subLabels)
return myTree
#分类
def classify(inputTree,labels,testVec):
'''
inputTree 训练好的决策树模型
labels 特征标签对应的标签名称
testVec 测试向量
'''
#得到根节点 root为特征的label
root = list(inputTree.keys())[0]
#得到根节点对应的value字典
valuedict = inputTree[root]
featIndex = labels.index(root)
key = testVec[featIndex]
valueOfFeat = valuedict[key]
print('+++', root, 'xxx', valuedict, '---', key, '>>>', valueOfFeat)
if isinstance(valueOfFeat,dict):
classify(valueOfFeat,labels,testVec)
else:
classifier = valueOfFeat
return classifier
def ContactLensesTest():
"""
Desc:
预测隐形眼镜的测试代码,并将结果画出来
Args:
none
Returns:
none
"""
# 加载隐形眼镜相关的 文本文件 数据
fr = open('../data/DecisionTree/lenses.txt')
# 解析数据,获得 features 数据
lenses = [inst.strip().split('\t') for inst in fr.readlines()]
# 得到数据的对应的 Labels
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']
# 使用上面的创建决策树的代码,构造预测隐形眼镜的决策树
lensesTree = creatTree(lenses, lensesLabels)
print(lensesTree)
dtPlot.createPlot(lensesTree)
if __name__ == "__main__":
ContactLensesTest()
Created on 2019/6/6
Author: ZJ
{'tearRate': {'normal': {'astigmatic': {'no': {'age': {'presbyopic': {'prescript': {'hyper': 'soft', 'myope': 'no lenses'}}, 'pre': 'soft', 'young': 'soft'}}, 'yes': {'prescript': {'hyper': {'age': {'presbyopic': 'no lenses', 'pre': 'no lenses', 'young': 'hard'}}, 'myope': 'hard'}}}}, 'reduced': 'no lenses'}}
![决策树图](https://img-blog.csdnimg.cn/20190606163651714.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMzU5MjY1,size_16,color_FFFFFF,t_70)