决策树总结

博客园相关内容值得一看。决策树模型根据当前数据集 D D D和属性集 A A A不断选定最优划分属性 a ∗ a_* a,根据最优属性 a ∗ a_* a的每个取值 a ∗ v a_*^v av产生一个分支子决策树,直到:

  • 样本全部属于同一类别,产生叶节点,标记为这个类别
  • 属性集 A A A为空或者剩下的数据集 D D D在任何属性上取值都一样,产生叶节点,标记为 D D D中最多的类别
  • 数据集 D D D为空,产生叶节点,标记为父节点 D D D中最多的类别

每个节点包含两个集合当前数据集 D D D和属性集 A A A,为了产生最优属性,一般希望 D D D尽可能属于同一类别,即纯度高,信息熵 E ( D ) = − ∑ p k l o g 2 p k E(D)=-\sum p_klog_2p_k E(D)=pklog2pk(其中 p k p_k pk是第 k k k类样本的比例)小。利用属性 a a a来划分数据集得到取值为 a v a^v av的数据集 D v D^v Dv,可以计算信息增益 G a i n ( D , a ) = E ( D ) − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E ( D v ) Gain(D,a)=E(D)-\sum_{v=1}^{V}\frac{|D^v|}{|D|}E(D^v) Gain(D,a)=E(D)v=1VDDvE(Dv) V V V a a a取值的个数), I D 3 ID3 ID3决策树就是每次取信息增益最大的属性来划分。实际上信息增益对取值数目较多的属性有偏好(因为取值较多的那个属性产生的分支多,每个分支的类别更有可能纯度更高),这使得决策树不具有泛化能力, C 4.5 C4.5 C4.5还依据增益率选择划分属性 G a i n _ r a d i o ( D , a ) = G a i n ( D , a ) I V ( a ) Gain\_radio(D,a)=\frac{Gain(D,a)}{IV(a)} Gain_radio(D,a)=IV(a)Gain(D,a),其中 I V ( a ) IV(a) IV(a)是属性 a a a的固有值(intrinsic value),定义为 I V ( a ) = − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ l o g 2 ∣ D v ∣ ∣ D ∣ IV(a)=-\sum_{v=1}^{V}\frac{|D^v|}{|D|}log_2\frac{|D^v|}{|D|} IV(a)=v=1VDDvlog2DDv a a a的取值数目越多这个值越大,信息增益率对取值数目较少的属性有偏好。实际 C 4.5 C4.5 C4.5使用了启发式:从 A A A中找到信息增益高于平均水平的属性,再从这些属性中找增益率最高的。 C A R T CART CART决策树利用基尼指数来选择属性: G i n i ( D ) = 1 − ∑ p k 2 Gini(D)=1-\sum p_k^2 Gini(D)=1pk2,基尼值越小,数据集纯度越高, C A R T CART CART决策树使用基尼指数 G i n i _ i n d e x ( D , a ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) Gini\_index(D,a)=\sum_{v=1}^{V}\frac{|D^v|}{|D|}Gini(D^v) Gini_index(D,a)=v=1VDDvGini(Dv)最大的那个属性作为最优属性。

决策树的分支太多会过拟合,通过决策树生成过程的预剪枝(结点划分不能提升泛化性能就不再分支)和后剪枝(自底向上对非叶结点考察,如果替换成叶节点泛化性能提升,就替换为叶结点)。预剪枝是在每次分支之前判断用验证集判断一下评估指标,如果有提高就分支,否则直接定为叶结点,预剪枝基于当下的“贪心”策略,可能导致欠拟合,因为这次分支可能不能提升性能,但这次分支后再分支可能使性能大大提升。后剪枝通过自底向上尝试替换非叶结点,如果验证集精度提高就进行替换,这样做欠拟合风险很小,泛化能力也优于预剪枝,但后剪枝操作的训练时间大大多余预剪枝和决策树生成。

对于有连续值的属性,可以对 D D D a a a的取值排序,尝试每个划分点 T a = { a i + a i + 1 2 ∣ 1 ≤ i ≤ n − 1 } T_a=\{\frac{a^i+a^{i+1}}{2}|1\le i\le n-1\} Ta={2ai+ai+1∣1in1},其中 n n n是连续值属性 a a a在数据集 D D D上的取值个数,根据划分点二分离散化 D D D后,即可根据离散值的判断方法来选择最优属性,当前结点划分属性为连续属性,该属性还可以作为后代结点的划分属性,只是分割点不同

若某些样本的某些属性有缺失值,可以定义 D ~ \tilde D D~表示 D D D在属性 a a a上没有缺失的那些样本子集, D ~ v \tilde D^v D~v表示取值为 a = v a=v a=v D ~ \tilde D D~的样本子集, D ~ k \tilde D_k D~k表示分类为第 k k k类的 D ~ \tilde D D~的样本子集,为每个样本 x x x定义一个权重 w x w_x wx(初始化为1),并定义三个比例:
ρ = ∑ x ∈ D ~ w x ∑ x ∈ D w x p ~ k = ∑ x ∈ D ~ k w x ∑ x ∈ D ~ w x r ~ v = ∑ x ∈ D ~ v w x ∑ x ∈ D ~ w x \rho=\frac{\sum_{x\in\tilde D}w_x}{\sum_{x\in D}w_x}\\ \tilde p_k=\frac{\sum_{x\in\tilde D_k}w_x}{\sum_{x\in\tilde D}w_x}\\ \tilde r_v=\frac{\sum_{x\in\tilde D^v}w_x}{\sum_{x\in\tilde D}w_x} ρ=xDwxxD~wxp~k=xD~wxxD~kwxr~v=xD~wxxD~vwx
ρ \rho ρ代表无缺失值样本的比例, p ~ k \tilde p_k p~k代表无缺失值样本中第 k k k类的比例, r ~ v \tilde r^v r~v代表无缺失值样本 a = a v a=a^v a=av的比例,信息增益即可推广为 G a i n ( D , a ) = ρ × G a i n ( D ~ , a ) = ρ × ( E ( D ~ ) − ∑ v = 1 V r ~ v ( D ~ v ) ) Gain(D,a)=\rho \times Gain(\tilde D,a)=\rho\times (E(\tilde D)-\sum_{v=1}^{V}\tilde r^v(\tilde D^v)) Gain(D,a)=ρ×Gain(D~,a)=ρ×(E(D~)v=1Vr~v(D~v)),信息熵推广为 E ( D ~ ) = − ∑ p ~ k l o g 2 p ~ k E(\tilde D)=-\sum \tilde p_klog_2\tilde p_k E(D~)=p~klog2p~k,这样即可在有缺失值的属性集上选择任意属性,若已经选择到了最优属性,分割数据集的时候 x x x在最优属性上没有缺失,就正常划分,若缺失了值,就把 x x x划分到所有分支数据集中,并且调整 x x x在这些取值为 v v v的分支中的权重为 w x = r ~ v w x w_x=\tilde r_vw_x wx=r~vwx,直观上看,这就是让同一个样本以不同的概率划分到不同子结点中

直观上看,这就是让同一个样本以不同的概率划分到不同子结点中 不理解什么意思

如果把每个属性视为一个维度坐标轴, d d d个属性描述的样本就对应了 d d d维空间中的一个点,每次产生分支实际是在寻找一个分类边界,而这个分类边界一定是与坐标轴平行的,对于复杂的问题,这样以坐标轴平行的分段来做出分割边界会导致时间开销很大,如果能采用斜的划分边界,就能使决策树模型大大简化,这样的决策树就是“多变量决策树”。这样的决策树每次划分数据集并不是以某个维度(即某个属性)的平行于坐标轴的横线(即具体取值)来做的,而是根据某些维度的线性组合来分割的,这样每个非叶结点是一个 ∑ i = 1 d w i a i = t \sum_{i=1}^dw_ia_i=t i=1dwiai=t的线性分类器,根据这个分类器来划分节点就能产生斜的决策边界,其中 w i w_i wi t t t也是由训练得到的

    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

《机器学习实战》第三章利用信息熵增益选择最优特征,下面的代码递归创建决策树

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                            

《机器学习实战》第九章构建 C A R T CART CART决策树,根据切分的误差最小来选择最优特征和阈值

    bestS = inf; bestIndex = 0; bestValue = 0
    for featIndex in range(n-1):
        for splitVal in set(dataSet[:,featIndex]):
            mat0, mat1 = binSplitDataSet(dataSet, featIndex, splitVal)
            if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN): continue
            newS = errType(mat0) + errType(mat1)
            if newS < bestS: 
                bestIndex = featIndex
                bestValue = splitVal
                bestS = newS

没有实现预剪枝,而实现了后剪枝

def prune(tree, testData):
    if shape(testData)[0] == 0: return getMean(tree) #if we have no test data collapse the tree
    if (isTree(tree['right']) or isTree(tree['left'])):#if the branches are not trees try to prune them
        lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal'])
    if isTree(tree['left']): tree['left'] = prune(tree['left'], lSet)
    if isTree(tree['right']): tree['right'] =  prune(tree['right'], rSet)
    #if they are now both leafs, see if we can merge them
    if not isTree(tree['left']) and not isTree(tree['right']):
        lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal'])
        errorNoMerge = sum(power(lSet[:,-1] - tree['left'],2)) +\
            sum(power(rSet[:,-1] - tree['right'],2))
        treeMean = (tree['left']+tree['right'])/2.0
        errorMerge = sum(power(testData[:,-1] - treeMean,2))
        if errorMerge < errorNoMerge: 
            print "merging"
            return treeMean
        else: return tree
    else: return tree

对于回归树,可以在叶节点用线性模型代替常数,这样是“模型树”

def linearSolve(dataSet):   #helper function used in two places
    m,n = shape(dataSet)
    X = mat(ones((m,n))); Y = mat(ones((m,1)))#create a copy of data with 1 in 0th postion
    X[:,1:n] = dataSet[:,0:n-1]; Y = dataSet[:,-1]#and strip out Y
    xTx = X.T*X
    if linalg.det(xTx) == 0.0:
        raise NameError('This matrix is singular, cannot do inverse,\n\
        try increasing the second value of ops')
    ws = xTx.I * (X.T * Y)
    return ws,X,Y

def modelLeaf(dataSet):#create linear model and return coeficients
    ws,X,Y = linearSolve(dataSet)
    return ws

def modelErr(dataSet):
    ws,X,Y = linearSolve(dataSet)
    yHat = X * ws
    return sum(power(Y - yHat,2))

我关于《统计机器学习》的决策树部分的代码实现 决策树模型实现:ID3,C4.5生成,剪枝,预测CART决策树(分类和回归)实现,CART算法生成,剪枝,交叉验证,预测

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_森罗万象

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值