python 决策树的底层逻辑

实验任务(实验题目、目的)

Implementing a binary tree and its common operations with VC++ or Python,and then use this tree to make decision or classification.
利用VC++/Python语言实现对二叉树的基本操作设计,用二叉树进行简单的判定或者分类,要求二叉树结点可以插入和删除。

任务分析

实现思路

构造就是生成一棵完整的决策树。简单来说,构造的过程就是选择什么属性作为节点的过程,那么在构造过程中,会存在三种节点:

  1. 根节点:就是树的顶端,最开始的那个节点。在上图中,“天气”就是一个根节点;
  2. 内部节点:就是树中间的那些节点,比如说“温度”、“湿度”、“刮风”;
  3. 叶节点:就是树最底部的节点,也就是决策结果。
    节点之间存在父子关系。比如根节点会有子节点,子节点会有子子节点,但是到了叶节点就停止了,叶节点不存在子节点。那么在构造过程中,你要解决三个重要的问题:
1. 选择哪个属性作为根节点;
2. 选择哪些属性作为子节点;
3. 什么时候停止并得到目标状态,即叶节点。
剪枝

剪枝就是给决策树瘦身,这一步想实现的目标就是,不需要太多的判断,同样可以得到不错的结果。之所以这么做,是为了防止“过拟合”(Overfitting)现象的发生。

过拟合:

指的是模型的训练结果“太好了”,以至于在实际应用的过程中,会存在“死板”的情况,导致分类错误。
欠拟合:指的是模型的训练结果不理想。
造成过拟合的原因:
一是因为训练集中样本量较小。如果决策树选择的属性过多,构造出来的决策树一定能够“完美”地把训练集中的样本分类,但是这样就会把训练集中一些数据的特点当成所有数据的特点,但这个特点不一定是全部数据的特点,这就使得这个决策树在真实的数据分类中出现错误,也就是模型的“泛化能力”差。

泛化能力:

指的分类器是通过训练集抽象出来的分类能力,你也可以理解是举一反三的能力。如果我们太依赖于训练集的数据,那么得到的决策树容错率就会比较低,泛化能力差。因为训练集只是全部数据的抽样,并不能体现全部数据的特点。

剪枝的方法:

• 预剪枝:在决策树构造时就进行剪枝。方法是,在构造的过程中对节点进行评估,如果对某个节点进行划分,在验证集中不能带来准确性的提升,那么对这个节点进行划分就没有意义,这时就会把当前节点作为叶节点,不对其进行划分。
• 后剪枝:在生成决策树之后再进行剪枝。通常会从决策树的叶节点开始,逐层向上对每个节点进行评估。如果剪掉这个节点子树,与保留该节点子树在分类准确性上差别不大,或者剪掉该节点子树,能在验证集中带来准确性的提升,那么就可以把该节点子树进行剪枝。方法是:用这个节点子树的叶子节点来替代该节点,类标记为这个节点子树中最频繁的那个类。
涉及的知识点

1. 采用信息增益率

因为 ID3 在计算的时候,倾向于选择取值多的属性。为了避免这个问题,C4.5 采用信息增益率的方式来选择属性。信息增益率 = 信息增益 / 属性熵
当属性有很多值的时候,相当于被划分成了许多份,虽然信息增益变大了,但是对于 C4.5 来说,属性熵也会变大,所以整体的信息增益率并不大。

2. 采用悲观剪枝

ID3 构造决策树的时候,容易产生过拟合的情况。在 C4.5中,会在决策树构造之后采用悲观剪枝(PEP),这样可以提升决策树的泛化能力。
悲观剪枝是后剪枝技术中的一种,通过递归估算每个内部节点的分类错误率,比较剪枝前后这个节点的分类错误率来决定是否对其进行剪枝。这种剪枝方法不再需要一个单独的测试数据集。

3. 离散化处理连续属性

C4.5 可以处理连续属性的情况,对连续的属性进行离散化的处理。比如打篮球存在的“湿度”属性,不按照“高、中”划分,而是按照湿度值进行计算,那么湿度取什么值都有可能。该怎么选择这个阈值呢,C4.5 选择具有最高信息增益的划分所对应的阈值。

4. 处理缺失值

针对数据集不完整的情况,C4.5 也可以进行处理。
使用的库

import numpy as np
import pandas as pd
import copy
from queue import Queue

全局变量

核心代码

#选择最佳特征
def chooseBestFeathear(trX,trY):
    global vis
    Ent=calcuCrossEntrophy(trY)
    sortList={}
    for i,item in enumerate(getFeathearNum(trX)):
        if i not in vis:
           ent=0
           for atrr in item:
              ent+=calcuCrossEntrophy(trY[trX[:,i]==atrr])
           sortList[i]=Ent-ent
    sortedList=sorted(sortList.items(), key=lambda d:d[1], reverse = True)
    return sortedList[0][0]
#计算熵增量
def calcuCrossEntrophy(classList):
    classCount={}
    sum=len(classList)
    crossEntrophy=0
    for vote in classList:
        if vote in classCount:
            classCount[vote]+=1
        else:
            classCount[vote]=1
    for key,value in classCount.items():
        crossEntrophy+=-(value/sum)*np.log(value/sum)
    return crossEntrophy
#搭建一棵决策树
def buildDecisionTree(root,X,Y):
    global vis
    if(len(vis)==feathearNum):
        root.isLeaves=1
        good=np.sum(Y)
        root.label="Good" if (good)*1.0/len(Y)>=0.5 else "Bad"
        return
    if np.sum(Y)==len(Y)|np.sum(Y)==0:
        root.isLeaves = 1
        root.label = "Good" if np.sum(Y)!=0 else "Bad"
        return
    bestFeathear=chooseBestFeathear(X,Y)
    feathear=getFeathearNum(X)[bestFeathear]
    for index in feathear:
        temp=Node()
        temp.cond=index
        # print(condition[bestFeathear+1])
        root.label=bestFeathear
        root.children.append(temp)
        vis.append(bestFeathear)
        buildDecisionTree(temp,X[X[:,bestFeathear]==index,:],Y[X[:,bestFeathear]==index])
        vis.pop()

实验结果
测试:

dT=decisionTree()
dT.Train(trX,trY)
print(dT.predict([2,1,2,1,1,1]))

苏苏

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值