• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

机器决策树算法后期预剪枝后剪枝

武飞扬头像
YanHi001
帮助1

1.在进行决策树剪枝操作之前,我们先来看看为什么要进行决策树的剪枝操作?

那是因为决策树的过拟合的风险很大。因为理论上来说可以将数据完全分的开,如果树足够大,每个叶子节点就剩下了一个数据。那么,这就会造成模型在训练集上的拟合效果很好,但是泛化能力很差,对新样本的适应能力不足。所以,对决策树进行剪枝,可以降低过拟合的风险。

2.决策树的剪枝策略(预剪枝/后剪枝)

  • 预剪枝

预剪枝在决策树生成过程中对每个节点先进行估计,如果划分能带来准确率上升则划分,否者不划分节点;后剪枝则是先使用训练集生成一棵决策树,再使用测试集对其节点进行评估,若将子树替换为叶子结点能带来准确率的提升则替换。

预剪枝优点:限制树的深度,叶子节点个数,叶子节点的样本数,信息增益量

  • 后剪枝

后剪枝则是先从训练集生成一棵完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能带来决策树泛化性能提升,则将该子树替换为叶结点。 

后剪枝和前剪枝的不同在于后剪枝是在生成决策树后再进行剪枝。顺序是由下到上

代码实现:

训练集:

学新通

测试集:

学新通

 则后剪枝代码为:

  1.  
    # 后剪枝
  2.  
    def post_prunning(tree , test_data , test_label , names):
  3.  
    newTree = tree.copy() #copy是浅拷贝
  4.  
    names = np.asarray(names)
  5.  
    # 取决策节点的名称 即特征的名称
  6.  
    featName = list(tree.keys())[0]
  7.  
    # 取特征的列
  8.  
    featCol = np.argwhere(names == featName)[0][0]
  9.  
    names = np.delete(names, [featCol]) #删掉使用过的特征
  10.  
    newTree[featName] = tree[featName].copy() #取值
  11.  
    featValueDict = newTree[featName] #当前特征下面的取值情况
  12.  
    featPreLabel = featValueDict.pop("prun_label") #如果当前节点剪枝的话是什么标签,并删除_vpdl
  13.  
     
  14.  
    # 分割测试数据 如果有数据 则进行测试或递归调用:
  15.  
    split_data = drop_exist_feature(test_data,featName) #删除该特征,按照该特征的取值重新划分数据
  16.  
    split_data = dict(split_data)
  17.  
     
  18.  
    for featValue in featValueDict.keys(): #每个特征的值
  19.  
    if type(featValueDict[featValue]) == dict: #如果下一层还是字典,说明还是子树
  20.  
     
  21.  
    split_data_feature = split_data[featValue] #特征某个取值的数据,如“脐部”特征值为“凹陷”的数据
  22.  
    split_data_lable = split_data[featValue].iloc[:, -1].values
  23.  
    # 递归到下一个节点
  24.  
    newTree[featName][featValue] = post_prunning(featValueDict[featValue],split_data_feature,split_data_lable,split_data_feature.columns)
  25.  
     
  26.  
    # 根据准确率判断是否剪枝,注意这里的准确率是到达该节点数据预测正确的准确率,而不是整体数据集的准确率
  27.  
    # 因为在修改当前节点时,走到其他节点的数据的预测结果是不变的,所以只需要计算走到当前节点的数据预测对了没有即可
  28.  
    ratioPreDivision = equalNums(test_label, featPreLabel) / test_label.size #判断测试集的数据如果剪枝的准确率
  29.  
     
  30.  
    #计算如果该节点不剪枝的准确率
  31.  
    ratioAfterDivision = predict_more(newTree, test_data, test_label)
  32.  
     
  33.  
    if ratioAfterDivision < ratioPreDivision:
  34.  
    newTree = featPreLabel # 返回剪枝结果,其实也就是走到当前节点的数据最多的那一类
  35.  
     
  36.  
    return newTree
  37.  
     
  38.  
    if __name__ == '__main__':
  39.  
    #读取数据
  40.  
    train_data = pd.read_csv('./train_data.csv')
  41.  
    test_data = pd.read_csv('./test_data.csv')
  42.  
    test_data_label = test_data.iloc[:, -1].values
  43.  
    names = test_data.columns
  44.  
     
  45.  
    dicision_Tree = {"脐部": {"prun_label": 1
  46.  
    , '凹陷': {'色泽':{"prun_label": 1, '青绿': 1, '乌黑': 1, '浅白': 0}}
  47.  
    , '稍凹': {'根蒂':{"prun_label": 1
  48.  
    , '稍蜷': {'色泽': {"prun_label": 1
  49.  
    , '青绿': 1
  50.  
    , '乌黑': {'纹理': {"prun_label": 1
  51.  
    , '稍糊': 1, '清晰': 0, '模糊': 1}}
  52.  
    , '浅白': 1}}
  53.  
    , '蜷缩': 0
  54.  
    , '硬挺': 1}}
  55.  
    , '平坦': 0}}
  56.  
    print('剪枝前的决策树:')
  57.  
    print(dicision_Tree)
  58.  
    print('剪枝前的测试集准确率: {}'.format(predict_more(dicision_Tree, test_data, test_data_label)))
  59.  
     
  60.  
    print('-'*20 '剪枝' '-'*20)
  61.  
    new_tree = post_prunning(dicision_Tree,test_data , test_data_label , names)
  62.  
    print('剪枝后的决策树:')
  63.  
    print(new_tree)
  64.  
    print('剪枝后的测试集准确率: {}'.format(predict_more(new_tree, test_data, test_data_label)))
学新通

 运行结果:

学新通

 剪枝后决策树不仅更加轻量,而且对于测试集的预测准确率从0.428提升到了0.714

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhggcffj
系列文章
更多 icon
同类精品
更多 icon
继续加载