机器学习实践(三)——决策树剪枝处理

在上次的实践中进行了决策树的构建,本次实践就在上次的基础上进行对决策树的剪枝处理。

一、为什么决策树要进行剪枝处理?

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

二、剪枝处理的基本放法

进行剪枝处理最基本的方法有两种:预剪枝与后剪枝。

1.预剪枝

就是在构造决策树的过程中,先对每个结点在划分前进行估计,如果当前结点的划分不能带来决策树模型泛化性能的提升,则不对当前结点进行划分并且将当前结点标记为叶结点。

优缺点:预剪枝使得决策树的很多分支没有“展开”,降低了过拟合的风险,还能够减少决策树的训练时间以及预测事件开销。但是,有些分支可能当前划分不能提升模型的泛化性能甚至导致泛化性能暂时下降,但在其基础上的后续划分可能显著提高模型的性能。预剪枝的这种禁止分支展开,同样也给决策树带来了欠拟合的风险。

2.后剪枝

后剪枝就是先把整颗决策树构造完毕,然后自底向上的对非叶结点进行考察,若将该结点对应的子树换为叶结点能够带来泛华性能的提升,则把该子树替换为叶结点。

优缺点:相比预剪枝,后剪枝的优点是后剪枝决策树通常比预剪枝决策树保留了更多的分支;后剪枝决策树的欠拟合风险很小,泛化性能往往优于预剪枝决策树。后剪枝的缺点是决策树训练时间开销比未剪枝决策树和预剪枝决策树都要大的多。

三、代码实现剪枝处理

1.数据集准备

本次使用的数据集在上次实践中使

用的数据集基础上进行了部分修改。

温度天气情况人员齐全情况场地情况是否适宜进行社团活动
晴朗齐全人较多
适中晴朗齐全宽敞
适中降雨齐全宽敞
降雨不齐全人较多
降雨不齐全拥挤
适中降雨不齐全宽敞
适中阴天不齐全宽敞
适中阴天齐全人较多
降雨齐全人较多
def createData():
    data = np.array([['高','晴朗','齐全','人较多'],
    ['适中','晴朗','齐全','宽敞'],
    ['适中','降雨','齐全','宽敞'],
    ['高','降雨','不齐全','人较多'],
    ['高','降雨','不齐全','人较多'],
    ['适中','降雨','不齐全','宽敞'],
    ['适中','阴天','不齐全','宽敞'],
    ['适中','阴天','齐全','人较多'],
    ['高','降雨','齐全','人较多']])
    label = np.array(['否', '是', '是', '否', '否', '否', '是', '否','是'])
    name = np.array(['温度', '天气情况', '人员齐全情况', '场地情况'])
    return data, label, name

 2.创建决策树并展现决策树

此部分代码在上次实践中展示,详情见完整代码。

决策树展现:

3. 创建剪枝决策树

def createTreePrePruning(dataTrain, labelTrain, dataTest, labelTest, names, method = 'id3'):
    trainData = np.asarray(dataTrain)
    labelTrain = np.asarray(labelTrain)
    testData = np.asarray(dataTest)
    labelTest = np.asarray(labelTest)
    names = np.asarray(names)
    # 如果结果为单一结果
    if len(set(labelTrain)) == 1: 
        return labelTrain[0] 
    # 如果没有待分类特征
    elif trainData.size == 0: 
        return voteLabel(labelTrain)
    # 其他情况则选取特征 
    bestFeat, bestEnt = bestFeature(dataTrain, labelTrain, method = method)
    # 取特征名称
    bestFeatName = names[bestFeat]
    # 从特征名称列表删除已取得特征名称
    names = np.delete(names, [bestFeat])
    # 根据最优特征进行分割
    dataTrainSet, labelTrainSet = splitFeatureData(dataTrain, labelTrain, bestFeat)

    # 预剪枝评估
    # 划分前的分类标签
    labelTrainLabelPre = voteLabel(labelTrain)
    labelTrainRatioPre = equalNums(labelTrain, labelTrainLabelPre) / labelTrain.size
    # 划分后的精度计算 
    if dataTest is not None: 
        dataTestSet, labelTestSet = splitFeatureData(dataTest, labelTest, bestFeat)
        # 划分前的测试标签正确比例
        labelTestRatioPre = equalNums(labelTest, labelTrainLabelPre) / labelTest.size
        # 划分后 每个特征值的分类标签正确的数量
        labelTrainEqNumPost = 0
        for val in labelTrainSet.keys():
            labelTrainEqNumPost += equalNums(labelTestSet.get(val), voteLabel(labelTrainSet.get(val))) + 0.0
        # 划分后 正确的比例
        labelTestRatioPost = labelTrainEqNumPost / labelTest.size 
    
    # 如果没有评估数据 但划分前的精度等于最小值0.5 则继续划分
    if dataTest is None and labelTrainRatioPre == 0.5:
        decisionTree = {bestFeatName: {}}
        for featValue in dataTrainSet.keys():
            decisionTree[bestFeatName][featValue] = createTreePrePruning(dataTrainSet.get(featValue), labelTrainSet.get(featValue)
                                      , None, None, names, method)
    elif dataTest is None:
        return labelTrainLabelPre 
    # 如果划分后的精度相比划分前的精度下降, 则直接作为叶子节点返回
    elif labelTestRatioPost < labelTestRatioPre:
        return labelTrainLabelPre
    else :
        # 根据选取的特征名称创建树节点
        decisionTree = {bestFeatName: {}}
        # 对最优特征的每个特征值所分的数据子集进行计算
        for featValue in dataTrainSet.keys():
            decisionTree[bestFeatName][featValue] = createTreePrePruning(dataTrainSet.get(featValue), labelTrainSet.get(featValue)
                                      , dataTestSet.get(featValue), labelTestSet.get(featValue)
                                      , names, method)
    return decisionTree 

(只粘贴了部分代码) 

 4.结果展示

 预剪前的树:

剪枝后的树:

 

四、总结

在时间开销上,预剪枝的训练时间开销降低、测试时间开销降低,而后剪枝的训练时间开销增加、测试时间开销降低。

在拟合风险方面,预剪枝的过拟合风险降低、欠拟合风险增加,而后剪枝的过拟合风险降低、欠拟合风险基本不变。

而后剪枝的泛化性能通常是优于预剪枝的。

完整代码:

链接:https://pan.baidu.com/s/1Zi7aZcCzWg3ug-2ligpatQ?pwd=3zfw 
提取码:3zfw

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
决策树算法是一种广泛应用于分类和回归的机器学习算法,它基于树形结构对样本进行分类或预测。决策树算法的主要思想是通过一系列的判断来对样本进行分类或预测。在决策树中,每个节点表示一个属性或特征,每个分支代表该属性或特征的一个取值,而每个叶子节点代表一个分类或预测结果。 决策树算法的训练过程主要包括以下步骤: 1. 特征选择:根据某种指标(如信息增益或基尼系数)选择最优的特征作为当前节点的分裂属性。 2. 决策树生成:根据选择的特征将数据集分成若干个子集,并递归地生成决策树。 3. 剪枝:通过剪枝操作来提高决策树的泛化性能。 决策树算法的优点包括易于理解和解释、计算复杂度较低、对缺失值不敏感等。但是,决策树算法也存在一些缺点,如容易出现过拟合、对离散数据敏感等。 下面是一个决策树算法的案例:假设我们要根据一个人的年龄、性别、教育程度和职业预测其收入水平(高于或低于50K)。首先,我们需要将这些特征进行编码,将其转换为数值型数据。然后,我们可以使用决策树算法对这些数据进行训练,并生成一个决策树模型。最后,我们可以使用该模型对新的数据进行分类或预测。例如,根据一个人的年龄、性别、教育程度和职业,我们可以使用决策树模型预测该人的收入水平。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值