• 决策树


    决策树基本上就是把我们以前的经验总结出来。这里有一个打篮球的训练集。假如我们要出门打篮球,一般会根据“天气”、“温度”、“湿度”、“刮风”这几个条件来判断,最后得到结果:去打篮球?还是不去?

    上面这个图就是一棵典型的决策树。我们在做决策树的时候,会经历两个阶段:构造和剪枝。

    构造

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

    1.根节点:就是树的最顶端,最开始的那个节点。在上图中,“天气”就是一个根节点;

    2.内部节点:就是树中间的那些节点,比如说“温度”、“湿度”、“刮风”;

    3.叶节点:就是树最底部的节点,也就是决策结果。

    节点之间存在父子关系。比如根节点会有子节点,子节点会有子子节点,但是到了叶节点就停止了,叶节点不存在子节点。那么在其实构造就是对应着三个重要的问题:

    1.选择哪个属性作为根节点;

    2.选择哪些属性作为子节点;

    3.什么时候停止并得到目标状态,即叶节点。

    剪枝

    决策树构造出来之后是不是就万事大吉了呢?也不尽然,我们可能还需要对决策树进行剪枝。剪枝就是给决策树瘦身,这一步想实现的目标就是,不需要太多的判断,同样可以得到不错的结果。之所以这么做,是为了防止“过拟合”(Overfitting)现象的发生。过拟合,它指的就是模型的训练结果“太好了”,以至于在实际应用的过程中,会存在“死板”的情况,导致分类错误。

    那么如何解决刚才构造的三个问题呢?

    第三个问题叶节点一般就是对应我们的目标,比如去或者不去

    而前两个问题可以合并成一个问题,那就是以最重要特征作为根节点以此类推

    那么如何计算特征的重要性呢?这里就需要用到信息熵这个概念:它表示了信息的不确定度。

     1 def entropy(elements):
     2     """
     3     计算熵
     4     (各个元素出现次数/总数 * (各个元素出现次数/总数)的对数)的总数取负
     5     :param elements:
     6     :return:
     7     """
     8     counter = Counter(elements)
     9     probs = [counter[c] / len(elements) for c in elements]
    10     return - sum(p * np.log(p) for p in probs)

    假设有 2 个集合

    集合 1:5 次去打篮球,1 次不去打篮球;

    集合 2:3 次去打篮球,3 次不去打篮球。

    在集合 1 中,有 6 次决策,其中打篮球是 5 次,不打篮球是 1 次。那么假设:类别 1 为“打篮球”,即次数为 5;类别 2 为“不打篮球”,即次数为 1。那么节点划分为类别 1 的概率是 5/6,为类别 2 的概率是 1/6,带入上述信息熵公式可以计算得出:

    同样,集合 2 中,也是一共 6 次决策,其中类别 1 中“打篮球”的次数是 3,类别 2“不打篮球”的次数也是 3,那么信息熵为多少呢?我们可以计算得出:

     

    很明显,如果按某特征区分后,样本越均匀,则信息熵越大。相反如果某特征带来的信息熵越小,那么它越好的,我们确定根节点则需要找到这个信息熵最小的节点就是了。

     1 def find_the_min_spilter(training_data: pd.DataFrame, target: str) -> str:
     2     """
     3     寻找分割后最小熵的分割特征
     4     :param training_data: 数据
     5     :param target: 目标特征
     6     :return:
     7     """
     8     # 将数据去除目标特征
     9     x_fields = set(training_data.columns.tolist()) - {target}
    10 
    11     spliter = None
    12     min_entropy = float('inf')          # 预先设置成正无穷
    13 
    14     for f in x_fields:                  # 循环所有特征名
    15         values = set(training_data[f])  # 取该特征所有数值做集合
    16         for v in values:                # 循环该特征所有数值集合
    17             sub_spliter_1 = training_data[training_data[f] == v][target].tolist()       # 计算等于该数值对目标特征分布
    18             entropy_1 = entropy(sub_spliter_1)                                          # 计算等于该数值时目标特征分布信息熵
    19             sub_spliter_2 = training_data[training_data[f] != v][target].tolist()       # 计算不等于该数值对目标特征分布
    20             entropy_2 = entropy(sub_spliter_2)                                          # 计算不等于该数值时目标特征分布信息熵
    21             entropy_v = entropy_1 + entropy_2                                           # 计算此数值对目标特征的总信息熵
    22 
    23             if entropy_v <= min_entropy:        # 如果信息熵小于当前最小信息熵则更新信息熵与特征
    24                 min_entropy = entropy_v
    25                 spliter = (f, v)
    26 
    27     print('spliter is: {}'.format(spliter))
    28     print('the min entropy is: {}'.format(min_entropy))
    29     print('----------------------')
    30 
    31     return spliter
  • 相关阅读:
    centos7启动redis命令
    临时和永久关闭Selinux
    坑人的Mysql5.7 (默认不支持Group By语句)(转)
    修改docker容器参数
    FastDFS常用命令
    SpringBoot集成RabbitMQ消息队列搭建与ACK消息确认入门
    git忽略.idan目录
    springboot2.x接口返回中文乱码
    解决ssh连接linux服务器速度慢
    基于SSD固态硬盘的数据库性能优化
  • 原文地址:https://www.cnblogs.com/bfmq/p/11999964.html
Copyright © 2020-2023  润新知