机器学习-周志华-个人练习4.4

4.4 试编程实现基于基尼指数进行划分选择的决策树算法,为表4.2中数据生成预剪枝、后剪枝决策树,并与未剪枝决策树进行比较。

本题未剪枝决策树与4.3题基本一致,同时,由于表4.2数据没有连续属性,因此本题的代码不能处理具有连续属性的数据XD。

事实上,在本题用基尼指数与用基于信息增益的效果是一样的,但由于多个变量可能同时达到最小基尼指数,因此我的代码结果和成图里面的“脐部=凹陷”这一节点采用的是根蒂进行划分(根蒂、色泽同时都是最优属性),这样一来,这个节点对应的验证集精度为1,无论预剪枝还是后剪枝都不能把它剪掉。

这道题的基尼指数我先进行了推导化简,在只有2类的情况下,Gini_ index(D,a)等价于,因此可以其代替原公式。

本题的未剪枝、预剪枝、后剪枝和生成树状结构都较多使用了递归,具体代码与决策树效果如下:

# -*- coding: utf-8 -*-
# exercise 4.4: 基于基尼指数的决策树算法,采用未剪枝,预剪枝,后剪枝处理(无连续属性)
import numpy as np
import igraph as ig
from collections import Counter
import random, copy

def all_class(D):  # 判断D中类的个数
    return len(np.unique(D[:,-1]))  # np.unique用以生成具有不重复元素的数组

def diff_in_attr(D,A_code):  # 判断D中样本在当前A_code上是否存在属性取值不同,即各属性只有一个取值
    cond = False
    for i in A_code:  # continuous args are excluded
        if len(np.unique(D[:,i])) != 1:
            cond = True
            break
    return cond

def major_class(D):  # 票选出D中样本数最多的类
    # 本书所给图4.6是利用信息增益划分得到的,在进行预剪枝时,将脐部=稍凹\
    # 判定为好瓜和坏瓜具有同样验证集精度和泛化误差,但若直接用22行进行计算\
    # 取第一项,则没有考虑到训练集含偶数个例子时,可能出现上述情况,为了和书\
    # 上一致,强行让这种情况下的分类取为1,即好瓜
    c = Counter(D[:,-1]).most_common()
    if len(c) == 1:
        return c[0][0]
    elif c[0][1] == c[1][1]:
        return 1
    else:
        return c[0][0]

def min_gini(D,A_code):
    N = len(D)  # 当前样本数
    dict_class = {}  # 用字典保存类及其所在样本,键为类型,值为类型所含样本
    for i in range(N):
        if D[i,-1] not in dict_class.keys():  # 为字典添加新类
            dict_class[D[i,-1]] = []
            dict_class[D[i,-1]].append(int(D[i,0]))
        else:
            dict_class[D[i,-1]].append(int(D[i,0]))
    Gini_D_A = {}  # 用字典保存在某一属性下的属性值及其所在样本,键为属性取值,值为对应样本
    for a in A_code:
        # A中的离散属性,在后期的迭代中,属性a可能会变得不连续
        dict_attr = {}
        for i in range(N):
            if D[i,a] not in dict_attr.keys():  # 为字典添加新的属性取值
                dict_attr[D[i,a]] = []
                dict_attr[D[i,a]].append(int(D[i,0]))
            else:
                dict_attr[D[i,a]].append(int(D[i,0]))
        # 对Gini_index(D,a)变形发现,在只有好瓜和坏瓜这两类时,基尼指数最小等价于
        # sigma(v=1到V)求和:(|Dv+| * |Dv-|) / |Dv|最小
        Gini_D_A[(a,)] = 0
        for av,v in dict_attr.items():
            m = len(v)  # m为当前属性取值的样本总数,如A_a0包含的样本总数
            x2 = len(set(v) & set(dict_class[1.0]))
            x1 = m - x2
            Gini_D_A[(a,)] += x1 * x2 / m
    Gini_D_A_list = sorted(Gini_D_A.items(),key=lambda a: a[1])
    best = Gini_D_A_list[0][0]
    dict
  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值