决策树的python实现

决策树和KNN是机器学习的入门级别的算法,所以面试的时候都时常会有面试官要求将决策树写出来以用来检验面试者的算法基本素养。

1.信息熵

信息熵是表示数据的混乱程度(物理学当中就有热熵来表示分子混乱程度)。信息熵表现为-log(信息的概率)

那么整体的信息熵的数学期望:对概率*-log(概率)求和,以下用代码语言表述上面所说:

from  math import log
def shannonent(dic):
    mm = {}
    dicLen= len(dic)
    shannonent = 0.0
    for elm in dic:
        mm[elm]=mm.get(elm,0)+1
    for key in mm:
        prob = float(mm[key])/dicLen
        shannonent -= prob*log(prob,2)
    return shannonent

举个例子:

>>> reload(thetree)
<module 'thetree' from 'thetree.py'>
>>> dic=['a','b','c','c','d','c','w','d','kd','kd','s','a']
>>> cc= thetree.shannonent(dic)
>>> cc
2.688721875540867
>>> 

第一层的数据划分:

做决策树都知道最后的结果是一个树形结构,从一个总的数据分开由某个属性分开由此将数据集分散开来,出现了第一层,第二层....

有了这个基本思路的情况下,就像做数学题从往外面一层一层的剥开,那么剥开的规则是是的信息熵最小

综合上面所说的基本思想,我们可以选取一些简单的例子,先实现第一层的数据划分:

def splitdataSet(udata,xais,value):
    reDataset=[]
    for line in udata:
        if line[xais]==value:
            newdata=line[:,xais]
            newdata.extend(line[xais+1,:])
            reDataset.append(newdata)
    return reDataSet

一般实现都是一点点实现,选择xais---表示某一列,value---表示某行的某个值,这些步骤都是实现层的分的必要步骤,下面就是要选择第一层从哪一列剥开最合适:

def choiceBestW(dataSet):
    labels = [ elm[-1] for elm in data]
    origshannon = shannonent(lables)
    kuan = shape(dataSet)[1]-1
    chang  = shape(dataSet)[0]
    bestInforGain = 0.0;bestFeature = -1
    for i in range(kuan):
        featList = [elm[i] for elm in dataSet]
        uniVals = set(featList)
        for word in uniVals:
            newer = splitdataSet(dataSet,i,word)
            prob = len(newer)/len(dataSet)
            newEntropy +=prob*shannonent(newer)
        infoGain = origshannon - newEntorpy
        if (infoGain > bestInfoGain):
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature

将第一层的最优剥开维度确定后,就可以开始2层的剥开了(数学的数列运算一样,如果是等差数列要知道前2个值才可以退出之后的N维数列),那么这个时候就要考虑这种决策树什么时候可以停止剥开。初步总结有两种情况:1、数据集中数据的类都是属于同一个类;2、数据集中的各个维度都被分完了--这个也是超级无奈了。当遍历了各个维度的时候结果中还是有多个类别混合在一起,那么这个要给这个分类定义一个类可以认为“少数服从多数”;

def majorityCnt(classlist):
    classCount = {}
    for vote in classlist:
        classCount[vote]=classCount.get(vote,0)+1
    sortedClass = sorted(classCount.iteritems,\
                         key=operator.itemgetter(1),reverse=Ture)
    return sortedClass[0][0]

接下来就是构建决策树的开始: 

def creatmytree(oridata,lables):
    diclist = [elm[-1] for elm in oridata]
    if diclist.count(diclist[0])==len(diclist):
        return diclist[0]
    if len(oridata[0])==1:
        return majorityCnt(diclist)
    bestFeat = choiceBestW(oridata)
    bestFeatLabel = lables[bestFeat]
    mytree ={bestFeatLabel:{}}
    del(lables[bestFeat])
    bestline = [elm[bestFeat] for elm in oridata]
    uniqvals = set(bestline)
    for val in uniqvals:
        nlabels = lables[:]
        mytree[bestFeatLabel][val] = creatmytree(splitdataSet(oridata,bestFeat,val),nlabels)
    return mytree

一般到这对原有数据的分类模型已经出来了,但是其作为有预测功能的分类还是没有出来,那么这个时候我们要将这个模型和一些未知分类的数据结合起来运用:

 

def classficate(testdata,trees,labels):
    firstStr = trees.keys()[0]
    secondDict = trees[firstStr]
    featIndex = featLabels.index(firstStr)
    for val in secondDict.keys():
        if testdata[featIndex] == val:
            if type(sencondDict[val])__name__ =='dict':
                classLabel = classficate(testdata,secondDict[keys],labels)
            else:
                classLabel = secondDict[key]
    return classLabel
#trees 是指上面得到的决策树模型
#testdata 是测试数据向量(一条数据)
#labels 是指测量数据的指标

现在将上面的代码合在一起就可以做出一些预测了,在机器学习实战这本书里面是对配眼镜流程的一个模仿,我们接下来会对数据进行一个实战:

突然想到一个决策树的一个应用场景:问卷设计方式(从科学的角度来说这是最快的方式)--通常在调查的过程中大家会有定性和定量结合起来,那么定性很多时候都是拍脑袋哪个先哪个后,个人感觉如果用树结构去做份问卷调查显然会高效很多。----我这个星期尝试下:

考虑心理层面的因素,如果是问卷的话可以在前面加一些放松受访者的受访心理,然后通过趣味答题,测出想要的东西。

posted @ 2016-09-01 18:14  xyt_cathy  Views(8650)  Comments(1Edit  收藏  举报