一、问题描述
人民生活水平越来越高,买车的人也越远越多,根据长期统计出的数据,对不同的车具有不同属性跟购买用户的满意度相互关联,通过数据的分析,可以给用户直接推荐更适合的车型,也可以给汽车销售商提供更好的进货建议。根据这些数据来对具有这些属性的车做预测,给买车的顾客提供测评的结果。测评结果有四种:(unacc,acc,good,vgood)分别代表(不可接受,可接受,好,非常好)
二、算法原理
原理:ID3算法,计算每个特征划分后的信息熵之后再按照信息增益的方法划分数据集。使用递归的方法构建树,直到程序遍历完所有划分数据集的属性,或者每个分支下的所有实例都具有相同的分类,如果所有实例具有相同的分类,则得到一个叶子借点或终止块,任何到达叶子节点的数据必然属于叶子节点的分类。
ID3决策树生成:
计算每个特征划分后的信息熵之后再按照信息增益的方法划分数据集。使用递归的方法构建树,直到程序遍历完所有划分数据集的属性,或者每个分支下的所有实例都具有相同的分类,如果所有实例具有相同的分类,则得到一个叶子借点或终止块,任何到达叶子节点的数据必然属于叶子节点的分类。
希望取a作为划分属性,划分到|V|个子节点后,所有子节点的信息熵之和即划分后的信息熵能够有很大的减小,减小的最多的那个属性就是我们选择的属性。
递归地调用,每次选择一个属性对样本集进行划分,直到两种情况使这个过程停止:
(1)某个子节点样本全部属于一类
(2)属性都用完了,这时候如果子节点样本还是不一致,那么少数服从多数
决策树的剪枝
决策树的剪枝主要是为了预防过拟合,主要思路是从叶节点向上回溯,尝试对某个节点进行剪枝,比较剪枝前后的决策树的损失函数值。最后我们通过动态规划(树形dp)就可以得到全局最优的剪枝方案。
三、数据描述及可视化
car.data(这是一个关于汽车测评的数据集,数据集包含1728个数据,每个数据包含6个属性变量,分别为「买入价」,「维护费」,「车门数」,「可容纳人数」,「后备箱大小」,「安全性」。6个属性变量全部是标称变量,比如「可容纳人数」值可为「2,4,more」,「安全性」值可为「low,med, high」,标签变量为汽车的测评结果)。
选取属性买入价和安全性作为样本,根据一般结果可以推测这两个属性对结果标签影响较大。
四、算法的程序实现
4.1 计算香农熵
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
4.2 选择最优的特征
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1 #the last column is used for the labels
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0; bestFeature = -1
for i in range(numFeatures): #iterate over all the features
featList = [example[i] for example in dataSet]#create a list of all the examples of this feature
uniqueVals = set(featList) #get a set of unique values
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 #calculate the info gain; ie reduction in entropy
if (infoGain > bestInfoGain): #compare this to the best gain so far
bestInfoGain = infoGain #if better than current best, set to best
bestFeature = i
return bestFeature #returns an integer
4.3 生成决策树
def createTree(dataSet,labels):
classList = [example[-1] for example in dataSet]
if classList.count(classList[0]) == len(classList):
return classList[0]#stop splitting when all of the classes are equal
if len(dataSet[0]) == 1: #stop splitting when there are no more features in dataSet
return majorityCnt(classList)
bestFeat = chooseBestFeatureToSplit(dataSet)
bestFeatLabel = labels[bestFeat]
myTree = {bestFeatLabel:{}}
del(labels[bestFeat])
featValues = [example[bestFeat] for example in dataSet]
uniqueVals = set(featValues)
for value in uniqueVals:
subLabels = labels[:] #copy all of labels, so trees don't mess up existing labels
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)
return myTree
五、测试结果
使用数据构建决策树,是否需要剪枝看测试结果
取10%的数据做测试数据 观察正确率
0.7267 | 1.0000 | 0.6628 | 0.8953 | 0.6570 | 0.6570 | 0.6395 | 0.6221 | 0.5930 | 0.5640 |
平均正确率:0.70174=70%
六、总结及体会
决策树首要考虑一个问题,即 根据数据集构建当前树应该选择哪种属性作为树根,即划分标准?最好的情况,一开始选择某个特征,就把数据集划分成功,即在该特征上取某个值的全是一类。最坏的情况,不断选择特征,划分后的数据集总是杂乱无章,划分的数据集合还是有正有负,这时只能用投票法,所以得出了一般结论: 随着划分的进行,我们希望选择一个特征,使得子节点包含的样本尽可能属于同一类别。
本次实验采用ID3算法(Iterative Dichotomiser 迭代二分器),基于信息增益即信息熵来度量纯度,决策树还有C4.5算法(Classifier 4.5,ID3 的后继算法),CART算法(Classification And Regression Tree),基于基尼指数度量(基尼不纯度,度量集合无序程度,从一个集合中随机的选取子项,度量其错误地分类到其他类别的概率)七、参考文献
【1】数据挖掘十大算法之决策树详解(1)
https://blog.csdn.net/baimafujinji/article/details/51724371
【3】Peter Harrington。《机器学习实战》
【4】python使用matplotlib绘制柱状图教程
http://www.jb51.net/article/104924.htm
非常感谢阅读!如有不足之处,请留下您的评价和问题 。