1.决策树与k近邻算法对比
- k近邻算法最大的缺点就是无法给出数据的内在含义,决策树的主要优势就在于数据形式非常容易理解.
- 决策树由结点和有向边组成,结点包含2种类型:内部结点和叶节点,内部节点表示一个特征或属性,叶节点表示一个类.
- 决策树分类时,从根节点开始,对实例的某一特征进行测试,根据测试结果,将实例分配到其子结点;这时,每个子结点都对应该特征的一个取值,如此递归地对实例进行测试并分配,直到达到叶结点,最后将实例分到叶节点的类中.
2.决策树的优缺点
- 优点
- 缺点
3.决策树的产生过程
(1)关键思想:
本次采用ID3算法;在决策树哥哥节点上应用信息增益准则选择特征,递归的构建决策树;
具体方法:
- 从根节点开始,对节点计算所有可能的特征的信息增益,选择信息增益最大的特征作为节点的特征,由该特征的不同取值创建子节点;由特征的不同取值可以将原数据集划分为几个不同的数据集,分别计算信息增益;
- 对子结点递归的调用上述步骤,构建决策树;
- 直到所有数据属于同一个分类或没有特征可以选择为止,得到最终的决策树.
(2)算法结束条件:
若当前数据集的所有实例都属于同一类k,则此时的决策树T为单节点,将类k作为该节点的类标记,并返回T;
若当前数据集的特征集为空,则将数据集中出现次数最多的类k作为该节点的类标记,返回该节点;
(3)创建决策树的流程:
检测数据集中的每个子项是否属于同一个分类:
if so return 类标签;
else
寻找划分数据集的决定性特征
划分数据集
创建分支节点
for 每个划分的子集
调用此函数并增加返回结果到分支节点中
return 分支节点
实现python代码如下:
输入为训练数据集和训练数据集对应的特征集;
<span style="font-size:14px;">def createTrees(dataSet,label):
classList = [example[-1] for example in dataSet]
#the label is totally same, end the iter
if classList.count(classList[0]) == len(dataSet): #数据集都属于同一个分类
return classList[0]
#only one feature, take th majority features
if len(dataSet[0]) == 1: #特征集为空,选择数据集中出现次数最多的类返回
return majorityLabel(classList)
bestFeatureIndex = chooseBestFeature(dataSet)
bestFeature = label[bestFeatureIndex]
myTree = {bestFeature:{}}
del(label[bestFeatureIndex])
featureValue = [example[bestFeatureIndex] for example in dataSet]
uniqueFeatureValue = set(featureValue)
for value in uniqueFeatureValue:
subLabel = label[:]
myTree[bestFeature][value] = createTrees(splitDataSet(dataSet,bestFeatureIndex,value),subLabel)
return myTree</span>
4.如何寻找决定性特征
划分数据集的基本原则是:将无序的数据变得更加有序.
划分数据集的方法:
(1)使用信息论度量信息:
- 熵(entropy)表示随机变量不确定性的度量.
x是一个取有限个值(可以取n个不同值)的离散随机变量,其概率分布为p(x=xi)=pi,i=1,2,...,n,则随机变量x的熵定义为H(x)=-(p1logp1+p2logp2+....+pnlog(pn))
熵依赖于x的分布,与x的取值无关,因此x的熵也可以写作H(p).0<=H(p)<=logn;熵越大,随机变量的不确定性就越大.
- 条件熵(condition entropy)H(Y|X)表示在已知随机变量X的条件下随机变量Y的不确定性.即随机变量X给定的条件下随机变量Y的条件熵,定义为X给定条件下Y的条件概率分布的熵对X的数学期望:
H(Y|X)=P1*H(Y|X=x1)+P2*H(Y|X=x2)+...+PN*H(Y|X=xn) 其中,Pi=P(X=xi)
- 当熵和条件熵中的概率由数据估计(特别是极大似然估计)得到时,所对应的熵与条件熵称为经验熵和经验条件熵
- 信息增益(information gain):表示得知特征x的信息而使得类y的信息的不确定性减少的程度
特征A对训练数据集D的信息增益g(D,A),定义为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差,即g(D,A)=H(D)-H(D|A),信息增益也称为互信息.
- 信息增益比(information gaim ratio):特征A对训练数据集D的信息增益比为其信息增益g(D,A)和训练数据集D的经验熵H(D)的比.信息增益比也是值越大越好.
信息增益表示由于特征A而使得对数据集D的分类的不确定性减少的程度,信息增益大的特征具有更强的分类能力;
根据信息增益准则的特征选择方法是:对训练数据集D,计算其每个特征的信息增益,并比较其大小,选择信息增益最大的特征.
计算数据集的熵的过程如下:即使用所有类标签的发生频率计算类别出现的概率.熵越高,混合的数据也就越多.
<span style="font-size:14px;">def calcShannonEnt(dataSet):
numbers = len(dataSet)
labelCount = {}
for featVector in dataSet :
featLabel = featVector[-1]
if featLabel not in labelCount.keys():
labelCount[featLabel] = 0
labelCount[featLabel] += 1
shannon = 0.0
for key in labelCount:
labelTimes = labelCount[key]
labelPro = float(labelTimes)/numbers
shannon -= labelPro*log(labelPro,2)
return shannon</span>
根据信息增益选择当前最优的划分特征代码如下:
<span style="font-size:14px;">def chooseBestFeature(dataSet):
numOfeatures = len(dataSet[0])-1
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0
bestFeatureIndex = -1
numOdata = len(dataSet)
for i in range(numOfeatures):
#get the ith column of dataSet
featureList = [example[i] for example in dataSet]
uniqueFeatureValue = set(featureList)
newEntropy = 0.0
for value in uniqueFeatureValue:
newDataSet = splitDataSet(dataSet,i,value)
prob = len(newDataSet)/float(numOdata)
newEntropy += prob * calcShannonEnt(newDataSet)
infoGain = baseEntropy - newEntropy
if (infoGain > bestInfoGain):
bestInfoGain = infoGain
bestFeatureIndex = i
return bestFeatureIndex</span>
(2)度量集合无需程度的方法是基尼不纯度,简单的说就是从一个数据集中随机选取子项,度量其被错误分类到其他分组里的概率.
5.使用决策树进行分类
使用决策树分类:
在执行数据分类时,需要决策树/用于构造决策树的特征向量.然后,程序比较测试数据与决策树上的数值,递归执行该过程直到进入叶子节点,最后将测试数据定义为叶子节点所属的类型.
实现代码如下:
实现tip:引入构造决策树的特征向量,方便程序确定此特征在数据集中的存放位置.
<span style="font-size:14px;">def classify(inputTree,featLabels,testVec):
firstStr = inputTree.keys()[0]
secondDict = inputTree[firstStr]
featureIndex = featLabels.index(firstStr)
for key in secondDict.keys():
if (key==testVec[featureIndex]):
if type(secondDict[key]).__name__=='dict':
classLabel = classify(secondDict[key],featLabels,testVec)
else:
classLabel = secondDict[key]
return classLabel
</span>
6.决策树的存储
构造决策树非常耗时,为了节省计算时间,最好能够在每次执行分类时,调用已经构造好的决策树.
为解决这个问题,引入python的pickle模块序列化对象:序列化对象可以在磁盘上保存对象,并在需要的时候读取,任何对象都可以执行序列化操作,字典对象也是.
实现代码如下:
<span style="font-size:14px;">def storeTree(inputTree,filename):
import pickle
fw = open(filename,'w')
pickle.dump(inputTree,fw)
fw.close()
def grabTree(filename):
import pickle
fr = open(filename)
return pickle.load(fr)</span>
实现多数表决的代码如下:
def majorityLabel(classList):
classCount = {}
for vote in classList:
if vote not in classCount.keys():
classCount[vote] = 0
classCount[vote] += 1
#descending the classCount according to the value of the label
sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]