机器学习笔记(四)——决策树的构建与可视化以及如何计算信息增益根据信息增益划分数据集本文以新的数据集(隐形眼镜数据集)为基础实现构建决策树,决策树的保存和加载,决策树分类的使用,决策树的可视化。知识就不过多总结了,就这四个方面着重介绍一下。首先我们对数据集有个大致的了解:这个数据来源于UCI数据库,有四个特征:age(年龄)、prescript(症状)、astigmatic(闪光)、tearRate(泪液产生率)和一个分类标签类。分类包括三种类型:硬质材料、软质材料和不应佩戴。为了方便处理,对样本进行如下处理:age:young—>0,pre—>1,老花—>2prescript:myope—>0,hyper—>1astigmatic:no—>0,yes—>1tearRate:reduced—>0,normal—>14.决策树的构建在构建决策树之前,先回顾一下前几个子模块的工作原理:先获取原始数据集,然后根据最优特征。当数据集特征大于两个时,经过第一次划分后,数据会向下传递到树的下一个节点,在这里进行数据划分。这个过程使用递归原理来处理数据集。分裂什么时候结束?当程序遍历完划分后的数据集的所有属性,或者每个分支下的所有实例都具有相同的分类时,则表示划分后的数据集结束。构建决策树的过程就是用每次划分的数据填充字典。当数据集被划分后,用数据填充字典也结束了。这个过程也是一个递归的过程,至此决策树的构建就完成了。代码如下:defCreateTree(DataSet):#获取所有特征标签index_list=list(DataSet.columns)#获取最后一列的类别(分类标签)label_series=DataSet.iloc[:,-1].value_counts()#判断类别最大标签数是否等于数据样本数,或者数据集是否只有一列iflabel_series[0]==DataSet.shape[0]orDataSet.shape[1]==1:returnlabel_series.index[0]#returnclasslabel#获取最佳特征列索引col=ChooseBF(DataSet)#获取最佳特征BestFeature=index_list[col]#将最佳特征依次填入字典TheTree={BestFeature:{}}#从标签列表中删除这个Featurelabeldelindex_list[col]#提取最佳分割列的所有属性值value_list=set(DataSet.iloc[:,col])#用递归的方法来构建一棵树,每次对象是value_list中值的当前最优特征:TheTree[BeatFeature][value]=CreateTree(splitSet(DataSet,col,value))returnTheTree递归函数的第一个停止条件是所有类标签都相同,递归函数的第二个停止条件是用完所有feature,即数据集不能进一步划分;字典变量TheTree存储了树的所有信息,BestFeature为当前最优特征。最后,代码遍历当前最优特征的所有属性值,在每次数据集划分时递归调用函数CreateTree(),传入参数为每次划分后的数据集,返回值会插入到字典TheTree,递归结束后,字典中会嵌套很多代表叶子节点信息的数据。获取TheTree字典如下:{'tearRate':{0:'nolenses',1:{'astigmatic':{0:{'age':{0:'soft',1:'soft',2:{'处方':{0:'无镜片',1:'软'}}}},1:{'处方':{0:'硬',1:{'年龄':{0:'硬',1:'nolenses',2:'nolenses'}}}}}}}}从左边开始,第一个关键字key是tearRate,表示在所有特征中,tearRate特征的信息增益最大,这个特征下,数据落(除)最快,这个关键字的值也是一个字典。第二个关键字是根据tearRate特征划分的数据集,这几个关键字的值就是tearRate节点的子节点。这些值可能是类标签,也可能是另一个字典。如果值为类标签,则子节点为叶节点;如果值为另一个字典,则子节点为判断节点,重复这种格式形成决策树。5.决策树的保存和加载保存决策树的方法有很多种,但是原理是一样的,就是序列化和反序列化。下面介绍两种方法。#第一种方法np.save('TheTree.npy',TheTree)read_tree=np.load('TheTree.npy',allow_pickle=True).item()第一种方法是使用numpy库中的save方法,可以将字典格式的决策树保存为npy文件;读取树的时候需要在method后面加上item(),因为我们存的数据是字典类型,如果是矩阵类型需要删除。#第二种方法importpickledefstoreTree(inputTree,filename):fw=open(filename,'wb')pickle.dump(inputTree,fw)fw.close()defgrabTree(filename):fr=open(filename,'rb')returnpickle.load(fr)第二种方法是使用pickle库的dump方法序列化数据。读取时,使用load方法加载数据。这里需要注意的是,无论是写还是读,都需要是二进制格式,否则会出错。6、利用决策树分类构建决策树后,可用于实际数据的分类。在进行数据分类时,需要传入决策树、特征标签列表和测试数据进行分类。然后程序将测试数据与决策树上的值进行比较,递归执行该过程,直到进入叶节点,最后的分类结果就是叶节点的类型。代码如下:#传入的数据是决策树,数据集的特征标签,测试数据defclassify(inputTree,labels,testVec):#获取决策树的第一个节点FirstStr=list(inputTree.keys())[0]#取第一个节点外的下一个字典SecondDict=inputTree[FirstStr]'''{'nosurfacing':{0:'no',1:{'flippers':{0:'否',1:'是'}}}}{0:'否',1:{'脚蹼':{0:'否',1:'是'}}}{0:'否',1:'yes'}'''#获取labels中第一个节点的索引feat_index=labels.index(FirstStr)#遍历字典中的keyforkeyinSecondDict.keys():#比较testVec中的值与树节点的值,如果到达叶子节点,则返回类标签iftestVec[feat_index]==key:#如果下一个字典还有字典,递归继续比较:classlabel=classify(SecondDict[key],labels,testVec)else:#获取类标签直到结束classlabel=SecondDict[key]returnclasslabel传入特征标签listlabels的作用是帮助确定每个最优特征在数据集中的索引,并使用index的方法找到当前列表中第一个与FirstStr变量匹配的元素,然后代码递归遍历整棵树,将测试数据变量testVec中的值与树节点的值进行比较,直到到达叶子节点,返回当前节点的分类标签。这里以SecondDict为例,用上一篇文章中的数据构建的树。它的作用是获取当前词典中最优特征(第一个关键词)的值,从而达到与测试数据递归比较的效果。classlabel=classify(inputTree,labels,[0,1,0,0])'''无镜头'''执行该函数,可以将传入的数据与原文中的数据进行对比,分类结果一致.7.决策树可视化决策树的主要优点是直观易懂。如果不能直观地展示,就无法发挥其优势。但是通过matplotlib库绘制决策树是一个非常复杂的过程,这里提供一个比较简单的偷懒方法。Graphviz是一个图形绘制工具,可以绘制很多图形结构,但是传入的数据需要是dot格式的,所以这里我们使用sklearn生成的决策树进行可视化。Graphviz需要手动下载,安装完成后需要配置环境,将文件夹的路径添加到系统变量的Path中,最后在cmd中输入dot-version。如果出现版本信息,则表示安装配置成功。决策树可视化代码如下:fromsklearnimporttreefromsklearn.treeimportDecisionTreeClassifierimportpydotplusimportgraphvizdefpic_tree(DataSet):#所有特征数据feature_train=DataSet.iloc[:,:-1]#类标签数据the_label=DataSet.iloc[:,-1]#unique会对类标签去重labels=the_label.unique().tolist()#用类标签在列表中的索引替换标签-转换成数字the_label=the_label.apply(lambdax:labels.index(x))#trainingdataclf=DecisionTreeClassifier()clf=clf.fit(feature_train,the_label)#绘图过程dot_data=tree.export_graphviz(clf,out_file=None,feature_names=['age','prescript','astigmatic','tearRate'],class_names=['nolenses','soft','hard'],filled=True,rounded=True,special_characters=True)#两种方法#1.使用graphviz生成PDF图像的库pic=graphviz.Source(dot_data)pic.render('lense')#2.使用pydotplus库将Dot格式转换为PDF#graph=pydotplus.graph_from_dot_data(dot_data)#returngraph.write_pdf("lense.pdf")这里生成决策树图片的方法也有两种,第一种是使用graphviz库的Source方法生成PDF图片,第二种是使用pydotplus库将Dot格式转成PDF。最后可视化图片如下:小结综上所述,关于决策树的相关知识已经介绍完毕,总的来说这个分类算法很容易理解,但是非常重要,因为它为后面学习随机森林打下了基础,而且各个算法有自己适合的环境,决策树也有自己的缺点,决策树的优点:计算复杂度不高,输出容易理解,对中间缺失值不敏感,它可以处理不相关的特征数据树可以可视化决策树的缺点:当决策树过于复杂时,会出现过拟合。表,数据的微小变化也会导致不同的树。当样本不平衡时,权重不同会导致树有偏。公众号【奶糖猫】后台回复“隐形眼镜”获取源码和数据供参考,感谢阅读。
