不管对决策树的知识了解有多少,这次通过一个简单的例子来就能够了解它的原理和明白实现的方法。
实际场景
对于一个眼科医生而言,当面对病人是否需要佩戴隐形眼镜时,只需要通过几个问题就能够判断出病人是需要带软,硬还是不能带隐形眼镜。因此我们的数据集就是病人的四个特征(‘age’, ‘prescript’, ‘astigmatic’, 'tearRate’)的组合以及对应的结论(‘soft’,‘hard’,‘no lenses’),获取数据点击这里,提取码tvj6
先加载数据,如下:
# 加载数据
def loadData():
bigString = open(r'路径\lenses.txt', 'r')
dataMat = []
for line in bigString:
curLine = line.strip().split('\t')
dataMat.append(curLine)
return dataMat
那么接下来看看关于这个问题的决策树是怎样的一个结构。
可以看出,医生通过不断地问一些问题,最后对病人做出结论,那么决策树的构建过程,实际上就是不断寻找最佳特征的过程,使得数据集每一个样本都能够在决策树上体现出来,对于IDE3决策树而言,指的就是用IDE3方法来筛选出最佳特征,关于IDE的计算方法,这里不再详细去讲,把重点更多地放在决策树的实现上。因为是用python实现,那么首先一个问题就是,决策树在python里面是一个怎样的数据结构?
- 拥有多个节点的决策树在python里面是一个拥有多层的字典结构,相当于字典里面套字典。
那么该如何构建?
先搭外层再搭里层。构建的顺序可以理解为,在最开始的时候,根据一个特征进行划分,形成了左右两个分支,然后每个分支各自筛选特征再构建分支,以此类推,重复这个过程直到无法形成分支。这个过程反映在python里面就成为了:
- 先创建一个字典,其键为父节点,值为左右两个子节点,如果子节点能够继续划分那么这个值就变成了字典结构,以此类推,决策树在python里面成为了内嵌式的多层字典结构
其具体的实现方式如下:
# 输入数据和特征标签,数据格式为多行多列,行指数据个数,列是数据特征,最后一列是数据的类别
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)
# 历遍特征值,每个特征值都执行createTree,这是递归思想
for value in uniqueVals:
subLabels = labels[:]
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
return myTree
对于决策树构建函数中其他涉及的函数,具体如下:
# 计算IDE
def calcShannonEnt(dataSet):
numEntries = len(dataSet)
labelCounts = {}
for featVec in dataSet: # the the number of unique elements and their occurance
currentLabel = featVec[-1]
if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0
for key in labelCounts:
prob = float(labelCounts[key]) / numEntries
shannonEnt -= prob * log(prob, 2) # log base 2
return shannonEnt
# 将根据特征和特征值数据集划分
def splitDataSet(dataSet, axis, value):
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value:
reducedFeatVec = featVec[:axis] # chop out axis used for splitting
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
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 classify(inputTree, featLabels, testVec):
firstStr = inputTree.keys()[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.index(firstStr)
key = testVec[featIndex]
valueOfFeat = secondDict[key]
if isinstance(valueOfFeat, dict):
classLabel = classify(valueOfFeat, featLabels, testVec)
else:
classLabel = valueOfFeat
return classLabel
总结
这一次我们重点在于IDE决策树的构造上,了解决策树在python是一个嵌套式的多层字典结构,通过递归来实现对决策树的构造,至于IDE的计算公式并未讲解,有时间再补充吧。
来源:CSDN
作者:DocPark
链接:https://blog.csdn.net/weixin_45288820/article/details/104365906