剪枝理论学习请参考如下网址:机器学习算法——决策树4(剪枝处理)_Vicky_xiduoduo的博客-CSDN博客_剪枝 机器学习

不管是预剪枝还是后剪枝,都需要对决策树进行“泛化能力”的评估。本节的实例讲解采用留出法评估决策树的泛化能力。故需要预留一部分数据用作“训练集”,一部分用作“验证集/测试集”。将西瓜2.0数据集随机划分成两部分,如下表所示。

表1 西瓜数据集2.0划分出的训练集
色泽根蒂敲声纹理脐部触感好瓜
青绿蜷缩浊响清晰凹陷硬滑
乌黑蜷缩沉闷清晰凹陷硬滑
乌黑蜷缩浊响清晰凹陷硬滑
青绿稍蜷浊响清晰稍凹软粘
乌黑稍蜷浊响稍糊稍凹软粘
青绿硬挺清脆清晰平坦软粘
浅白稍蜷沉闷稍糊凹陷硬滑
乌黑稍蜷浊响清晰稍凹软粘
浅白蜷缩浊响模糊平坦硬滑
青绿蜷缩沉闷稍糊稍凹硬滑
表2 西瓜数据集2.0划分出的验证集/训练集
色泽根蒂敲声纹理脐部触感好瓜
青绿蜷缩沉闷清晰凹陷硬滑
浅白蜷缩浊响清晰凹陷硬滑
乌黑稍蜷浊响清晰稍凹硬滑
乌黑稍蜷沉闷稍糊稍凹硬滑
浅白硬挺清脆模糊平坦硬滑
浅白蜷缩浊响模糊平坦软粘
青绿稍蜷浊响稍糊凹陷硬滑

本节先讲预剪枝。

以ID3算法生成决策树,生成的决策树如图1所示(实现代码参考:机器学习算法——决策树6(划分属性选择实例)_Vicky_xiduoduo的博客-CSDN博客)。

图1 基于表1生成的未剪枝决策树 

基于图1,我们会选取“脐部”来对训练集进行划分,并产生三个分支,即平坦、凹陷、稍凹。

是否应该进行这个划分?预剪枝需要对划分前后的性能进行估计。

在划分之前,所有样例集中在根节点,若不进行划分,则根据决策树算法,该节点将被标记为叶节点,其类别标记为训练样例数最多的类别,假设这个叶节点标记为“好瓜”,那么看验证集表2,只有{4,5,8}分类正确,{9,11,12,13}分类错误,则验证集的精度为\frac{3}{7} \times 100%=42.9%

用“脐部”划分之后,如图2所示。节点②包含的编号为{1,2,3,14},③包含的编号为{6,7,15,17}、④包含的编号为{10,16}.因此,三个节点被标记为{好瓜,好瓜,坏瓜}。此时,验证集中{4,5,8,11,12}的样例被分类正确。验证集精度为\frac{5}{7} \times 100% = 71.4%>42.9%,于是用“脐部”进行划分得以确定。

根据构成的决策树的第二层进行划分决策:

然后决策树对“色泽”进行划分,编号{5}的验证集样本分类结果由正确转为错误,使得验证集精度为\frac{4}{7} \times 100%=57.1%,于是预剪枝策略将禁止节点“色泽”划分。

然后对“根蒂”进行划分,划分后验证集精度仍为71.4%,不能提升精度,所以禁止节点“根蒂”划分。

对“坏瓜”,其所训练样例已属于同一类,不再进行划分。

综上,这是一棵仅有一层划分的决策树,亦称为“决策树桩”。预剪枝决策树可能会带来“欠拟合”风险。

图2 生成的预剪枝决策树

预剪枝代码实现过程中其实就是调参过程

在sklearn中,实际就是调整以下几个训练参数:
min_samples_leaf             :叶子节点最小样本数。
min_samples_split            :节点分枝最小样本个数
max_depth                         :树分枝的最大深度
min_weight_fraction_leaf :叶子节点最小权重和
min_impurity_decrease    :节点分枝最小纯度增长量
max_leaf_nodes                :最大叶子节点数

一般来说,只调这三个        :max_depth,min_samples_leaf,min_samples_split

根据调参,预剪枝决策树采用Max_depth=1,min_samples_leaf=3。

用sklearn实现,代码如下:

import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
import graphviz
import matplotlib.pyplot as plt
import numpy as np
train_data = pd.read_csv('D:/Machine_Learning/西瓜数据集2.0划分出的训练集.csv', encoding='GBK')
test_data = pd.read_csv('D:/Machine_Learning/西瓜数据集2.0划分出的验证集.csv', encoding='GBK')
test = []
#进行ID3拟合
#创建LabelEncodet()对象,用于序列化
label=LabelEncoder()
for col in train_data[train_data.columns[:-1]]:
    train_data[col] = label.fit_transform(train_data[col])

label_test=LabelEncoder()
for col in test_data[test_data.columns[:-1]]:
    test_data[col] = label.fit_transform((test_data[col]))

#使用id3构建决策树
id3 = DecisionTreeClassifier(criterion='entropy',
                                     random_state=30,
                                     max_depth=1,
                                     min_samples_leaf=3
                                    )
id3 = id3.fit(train_data.iloc[:, :-1].values.tolist(), train_data.iloc[:, -1].values)
score_test = float(id3.score(test_data.iloc[:, :-1].values.tolist(),test_data.iloc[:, -1].values))
print(score_test)#精确度
#画出决策树
labels = ['色泽', '根蒂', '敲击', '纹理', '脐部', '触感']
dot_data = export_graphviz(id3,
                                feature_names=labels,
                                class_names=['好瓜', '坏瓜'],
                                filled=True,
                                rounded=True,
                                fontname="Microsoft YaHei")
graph = graphviz.Source(dot_data)
graph.render("tree5")

得到的图形如下:

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐