版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、随机森林实验报告实验目的实现随机森林模型并测试。实验问题Kaggle第二次作业Non-linearclassification算法分析与设计一.算法设计背景:1 .随机森林的原子分类器一般使用决策树,决策树又分为拟合树和分类树。这两者的区别在于代价估值函数的不同。2 .根据经验,用拟合树做分类的效果比分类树略好。3 .对于一个N分类问题,它总是可以被分解为N个2分类问题,这样分解的好处是其决策树更加方便构造,更加简单,且更加有利于用拟合树来构建分类树。对于每一个2分类问题,构造的树又叫CART树,它是一颗二叉树。4 .将N个2分类树的结果进行汇总即可以得到多分类的结果。5 .CART树构造:输
2、入;训练数据集D,停止训练条件输出!CART决策树根据训练数据集.从根节点开始.递归地时每个节点进行以下操作递归构造二叉决策树CD设节点的训练数据集为D*计算现有特征对该数据集的基尼系数,此时.对每一个特征A,对于每一个可能的划分值a,根据大于a及小于等干a将训练数据集分成口LD2两部分。计算gini系数公式如下:Gi福丽需*Gini(Dl+器*Gini(D2);Gini(D)=1-(2)在所有可能特征A以及其所有可能划分点a中,选择欧ni系数最小的特征及切分值,将D1和D2分配到左右两个子节点去:(3)对左右节点分别递归的调用(1),(2L直到满足一定条件为止.6 .随机森林构造:(1) 随
3、机取样,降低树与树之间的关联性RF在每次构造一棵决策树时,先随机的有放回的从训练集中抽取C60%)或n(sizeoftrainingset)个样本D.在每个节点分裂前,先随机从总共M个特征中选取m个(m«Mt一般取根号M)作为分裂用的候选特征,这有效降f氐了树与树之间的关联性.二.算法思路:将一个N分类问题转化为N个二分类问题。转化方法是:构造N棵二叉拟合树,这里假设N为26,然后我们给N棵二叉树依次标号为1,2,3.26。1号树的结果对应于该条记录是不是属于第一类,是则输出1,否则输出0.2号树的结果对应于该条记录是不是属于第二类,是则1否则0,依此类推。这样,我们的26棵二叉树的
4、结果就对应了26个下标。例如对于某条记录,这26个二叉树的结果按序号排列为0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,.1,0,那么这条记录的分类应该为25。要将一个26维的0,1序列变回一个索引,我们只需要找出这个序列中值最大的元素的索引,这个索引即是序列号。我们将上面的26棵分别对26个索引做是否判断的二分类树视为一个整体,在多线程的环境下,构造多个这样的整体,然后进行求和运算,最后取出每个结果序列中值最大的元素的下标作为分类值,那么久得到了我们想要的结果,随机森林完成。三.算法流程:1 .读入训练集trainset,测试集testset2 .将训练集分割为输入trainI
5、n,输出trainOut3 .这里假设类别数N为26,将trainOut记录条数映射为transformTrainOut训练记录数264.初始化transformTestOut测试记录数26全部为05 .Fori=1:ForestSize:/对训练集采样,这里要注意输入和输出一致sampleIn,transformSampleOut=TakeSample(trainIn,transformTrainOut)Forcategory=1:26:/CartTree数组存放着26棵二分类树CartTreecategory=TrainCartTree(sampleIn,transformSampleOu
6、t);end/transformTestOut测试记录数26为承接二分类树输出的容器fori1=1:testSetNum:Forcategory=1:26:transformTestOuti1category+=predict(CartTreecategory,testseti1)endEndEnd6 .遍历transformTrainOut口,将其每一行的最大值的下标作为该行记录的索引值。四.决策树及随机森林的配置1 .决策树在这里,我彳门每一次26分类是由26棵CART共同完成的,CART的costfunction采用的是gini系数,CART的最大层数为7,分裂停止条件为当前节点GINI
7、为0或者当前节点所在层数到达了7.2 .随机森林a.随机森林每次循环的训练集采样为原训练集的0.5.b.对于森林中每一棵决策树每一次分割点的选取,对属性进行了打乱抽样,抽样数为25,即每次分割只在25个属性中寻找最合适的值。并且对于每个选取的属性,我们进行了行采样。即如果这个属性所拥有的属性值数大于30,我们选取其中30个作为分割候选,如果小于30,则全部纳入分割候选。五.代码详解1.训练集/测试集的读入a.在dataDefine.h中定义了:#defin*numparametres613/619中防#deftnetrainsetNum(5239/10C# defineWstsMhlum1&a
8、mp;M/100试集的记录条0(# definetypeshlum26/2E/类# definenodesNum2C0/200J/Wffi一点数训练集记录列数numparametres(ID(1)+参数数量(617)+输出(1)=619)训练集记录条数transetNum测试集记录条数testsetNum分类类型数typesNum而在main.cpp中,我们声明了全局变量doubletrairJntrain5etNumnumparametre5-2;/训A.doubletrainOuttrain$etNum1;"训魂生的!UidoubleteslintestsetNumnumpara
9、metres-2;I".doublelestOut:es::t?:Nurn;)inttrainTDItrainsetNuml/川螃ft-fjieSffifl口,这个看其标情况有设有威决定LinrttertlDhestsetNum;/柒试里用一行记录的2trainIn用于装载训练集输入,trainOut用于装载训练集的输出(这里trainOut是二维数组是出于模型如果泛化,那么输出值不一定只有一个的情况,在本次实验中并未派上什么真正用场,可以将trainOut看作一个普通一维数组)。trainID用于装载训练集中每一行的第一列ID号。testIn,testID则对应测试集的输入和ID号
10、。这里注意,没有testOut的原因是测试集的结果理论上应该是不存在的。然后通过自己编写的读入函数readData(utrain,csv"ftest.csv'1读入测试集合训练集,这个函数将分别装载我们在前面提到的trainIn、trainOut、trainID、testIn、testID。这个函数使用的fstream逐行读入的方法,这里不做详述。2 .训练集输出转化为对应的26维01数组transformOuttypesNum在dataDefine.h中,我们定义了分类类别数typesNum:在main.cpp中,我们定义了全局变量transformOuttypesNumi
11、nttransformOuttrainsetNumtypesNum+1=0;类另(J款这里的transformOut是用于储存将trainOut每行的值映射为一行对应的26维01序列后所产生的结果。这里面的对应关系是:例如trainOut10中的值是13那么transformOut1013=1,transformOut10除13外其他列=0;如果值是14,那么14列为1,其他列为0,行号代表的是它们对应的是第几条记录;trainOut10和transformOut10都表示的是第10行的分类值为某个值,只是表达方式不同。前者用数字表示,后者将对应下标的值置1表示。转换接口由main.cpp中的
12、函数voidindexTransform(inttransforrmresllln+lrdoubleogreslj);f号化型辎出定义,它的输入参数依次为转换输出的承接容器transformres,盛放原始输出的容器orges。它所做的事情是将transformresiorgesi的值置13 .并行构建随机森林在main.cpp中,我们构建了doubletraininPerTimeTimeNumllmmparametres-2;doubletrainInPerTimeTlerTimeNum,-.m:,'3inetre:2;doubletrainInPerTimeT2perTimeNum
13、numparametres-2;doubletrainInPerTimeT3?erTiimeNumnumparametres-2;doubletrain!nPerTimeT4lerTieNurJ1-l.mr?"?me:re:-2;inttransfornnOutPerTime):mNul-+1|=(0);inttransfbrmOutPerTimeTl5erTiimeNumtypesNum+1=0;inttransform0utPerTimeT2ferTimeNumesNum+1=0;inttransformOutPerTimeTSleNumtypesNum+1=0;inttrans
14、fbrmOurtPerTimeT4pe'meNum7)esNum+1=0;doubletransformTestOutTl?s:setNum:Il1+1:0;doubletransformTestOutT2testsetiNum1ypesNum+1=0;doubletransformTestOutTBtestsetNumtypesNm+1=(0;doubletransformTestOutT4tes:setNL,nn:pwNunn+1=Q;trainInperTime代表的是随机森林算法中经过采样步骤后选取的训练输入,TransformOutPerTime代表的是与trainInper
15、Time对应的转换输出transformtestOut是承接本支线程的所有CART树的决策值之和的结构,这与算法思路是对应的,我们将所有CART树的预测结果在意个转换输出容器上累加,然后对于每行取该行最大列的下标,即可得到由随机森林得到的分类结果。我们可以看出,这几个变量都是只有最后的TX有区别,实际上,重复的创建相似的变量只是为了方便多线程操作不会冲突。多线程入口:decisicnT-ee&tasd-Treel;threadthreadlfmainlnThread,trarsformOutPerTim&Tl,trainlnPerTimeTl,.transformTestOut
16、TlrSiTreel);treacthreadfmairilnThread,transformOiJtPerTiin&Ti,trainlnPerTimeTi,transfomnTestOutT2,&Tree2);threadthread3(nnainnThread,transformOutPeirTimeT3,trainInPerTimeTS,transfornnTestOutTS,8lTnee3);threadthread4(mairinThreadrtran5formOutPerTim&T4,trainIrPerTimeT4,transformTestOutT4,8
17、tTree4);这里使用的是C+11的<m乃2>库,简单好用。每一个线程的随机森林框架定义在main.cpp的这个函数采用循环的方式,每次循环,对训练集及对应转换输出进行打乱后采样,然后输入TRAIN(trainInPerTime_HtransformOutPerTimejtransformTestOutTree);中进行一轮决策树的训练,这一轮训练将会生成26棵CART树,又应26个分类值。这里输入的参数Tree就是我们所用的决策树容器,这里注意,我们一个线程中只需要公用一个决策树结构即足够了在训练完成后,我们用transformTestOutij=1累加训练结果。4 .一轮训练
18、26棵树因为26棵CART树才能完整的等价于一棵26分类树,因此我们将构建这26棵CART树的过程看成是一个整体。这个过程由函数TRAIN(trainlnPerTimetransformOutPerTimetransformTestOutTree);实现。它的输入依次是本轮的训练输入(经过了下采样,随机森林要求的),对应的转换训练输出,以及一个决策树容器Tree。决策树的定义我们将在下文中描述。这个函数有一个栈就mck<int>tac区用于追踪树的遍历过程,这里我们假定用的是先根遍历;并且有一个从1:26的循环for(inttypesN=1;typesN<=typesNum;
19、typesN+)每次循环会建立一棵关于对应的分类值得CART树,CART树的构造是由栈trace维护的,trace维护的是一个先序的遍历顺序。当循环完成后,将会计算本轮的转换输出结果的变更:for(inti=0;i<testsetNum;+i)/testresPerTimeitypesN=TreexompuiteRes(testIni);transformTestOut_itypesN+=(*Tree),computeRes(testIni);5 .每科CART树的构造CART树的数据结构如下:ttructdecisionTree(doubletrain!nperTneNumnumpar
20、ametres-2;inttrairiOut"Tin-f1;nod£Nodes,归U;/每硅树时群要使用的可用节点索弓N记录intusabieNode,trainIntrainOut对应于输入该树的输入输出集,Nodes表示的是节点序列,在这里我们的树的构造使用的是数组,且树的节点间的索引是通过索引值维护的,这颗树非常紧密(如果只看NODES是看不出节点间的层级关系的)。它有如下成员函数:deeisionTreeO;voidsetDecisionTree(doubIe1rainln_(.rJime7?-2JdinttrainOut_);boolgetPartitionfin
21、tindex,intcontainert)-doublecomputeGinifintindex,intlabel,doublevalue);/doublecomputehlodeGini(intindex);doublecomputeRes(double-2);用于做掘的节点分割/用千计算53期节点时所需要的中曲值"计算某一节点的GE讥陶完感后.用于预测的函物,输入呈测试输入向量voidgetNodesSequence(iodel);初始化树voidinitializefnoJeele);“对于每个节点的一些操作voidgetNodeAttrfectai<int>sel
22、ectedCols,intindex);voidcomputePerNodeGirii(intindex);voidconAputeNodeValue(intindex););setDecisionTree用于给trainIn和trainOut赋值getNodeSequence(node1)本来是用来输出节点参数的,这里不做详述initialize用于初始化决策树。getNodeAttr用于得到某一节点的备选属性分割值computePerNodeGini用于计算某一节点的GINI值,这在停止节点分割时有用computeNodeValue是用于计算某一叶子节点的拟合值的。我们再说一下Nodes节
23、点,它的结构如下vector<trd>dataltidex;"用于装通市点的数据的容器”用于记录诙节点的分智峙.ectc<double>attributes!'.-n;intleftChiId,rightChild;子ij卓的1ndexintisLeat"0表示内部节点,1质示外部节点intsplitLabel;”记录当前的分割璃性的位置doublelabelvalue:/节点分割值doublevalue;“该节点的平均忙.用于拟合时的运算intlayer;"用于记录所在层数doublegint/当前节点的mi值Attrbutess
24、electedColumns是用于存放候选的分割值的容器其余变量的功能见图片中的文字注释这里我们用dataIndex存放对应记录所在索引的方法取代了直接存放记录,这里是一个巨大的改进,将程序的执行速度提高了至少10倍。在构造一棵决策树时,当train函数对应的trace栈的栈顶非空时,我们会不断的取出栈顶元素,对其进行boolgetP3rtitionfintindex,intcortairerO);.。用3一口;可於点笑:到操作,Index指的是节点所在的索引值,container用于存放这个节点的左右叶子索引,由于树的构建是由外部栈维护的,所以这个container是必不可少的,在当前节点分
25、割完成后,我们会将这个节点的索引值出栈,如果container0的值不是-1,我们会将container0,container1入栈。建树的又中应模块在main.cpp下的train函数中的trace.push(uj;树的初始化(插入头节点)完成后,正式开始决策树的构建while(!ta仁巳ernpty()intcurrent_node=trace.topQ;trace,popO;intcontainer2=0;(*Tree).getPartition(currentnode,container);判断当前节点是否成功分割if(ontainr0上一)trace.push(containerl)
26、;trace.push(container0);|训练完成,计算输出卜面再重点说一下函数:booldecisionTree:getPartition(intindex,intcontainer2)这个函数是单棵决策树构造的核心,调用这个函数,如果当前节点的Gini值已经为0,那么这个函数会计算当前节点的拟合值:HULX工正安七LUI”值ifip*odMihdex.gmiQ|NadMihdex.layer>=MaxLayerNum/*|/*Nodesiinidex.dataSetjizeQ<10*/)Nade5(indejc.i5LMf-1;“计算叶子节点的拟合值doublesum=
27、0;for(inti=0;i<Nodesndex.datalndex.size();+i)sunn+=trainOutNodesindex).dataindexiij;/Nodesindex,resi;Nodeslindexvalue-=sum/iNodesindex.dataIndex.sizeOcontainer0=tontainerl|=-1;returnfalse;结束条件是gini=0|层数等于10如果当前节点不满足结束分割条件,那么函数将对属性进行抽样,抽样的方法是打乱后取前selectedColumns歹U。然后调用getNodeAttr(s,index)获取当前节点的备选
28、分割值,这里的s是抽取的属性的列号的集合。/献得打乱后的索引.并选取前面的”个作为选取的列的索引,传递给羽3也获得所褥要的分割值vector<pairl>sequence(numparar"etre<-2);srand(unsigned)tinw(JU.);for(i=Oj<sequence.sizeO;+i)tjequenwlil.index-i;sequenee(i.value-rand。;)std::5ort(sequence.beginQ,sequerice.end(),cmp);vec:or<init>s(LeectT;Cfor(inti
29、=0;ii<SdectedCdumns;+i)同i=sequ«nce|i.index;)。启tNodeRttrfs.ind白x):在得到备选的属性分割值后,将进入循环,寻找最优分割点/Noces|inde|getAnricutesisj:fori=。:iSelectedColumns;+i)vertor<double>"iteratorcursorfar(cursor=Nodes(index.attributtsi.b&ginfl;cursor1=Nodesindex.attributesi.end();*.cursor)iempgini=conn
30、puteGini(inde>:,s|iL*cursor);if(mingini>temp,gini)min_gini-temp_gini:paMabel-si;par_vmluE=*cursor;)6 .最终结果计算在main函数中,我们将四个线程所得的transformOutT相加,最后遍历取每一行最大值的下标,即可得到最终结果。六.算法优化1 .应用了数组+栈建树取代了普通的函数递归建树,加快了建树速度。2 .在传递每个节点的节点数据集时,使用了传递数据集的索引而非数据本身,这样做的好处是,原来如果传递一条数据需要复制617个double类型的数量,而现在只需要传递一个Int型
31、的索引,这种快了617倍的数据集传递方式使程序运行效率提高了10倍以上。3 .在每个属性中选择备选分割值的时候,采用了一种下采样的策略。即:如果该节点的数据集大小小于某一数值,则将这个数据集的这个属性的所有值都纳入候选分割值列表。但是如果大于了这个阈值,则将属性所对应的列进行排序后再进行等间距采样得到样本数等于阈值的子集作为候选分割集。代码详见getPartition().这样做的好处是需要计算的分割gini值大大减少了(本人取的采样阈值时100,相比原数据集,样本空间缩小了尽30倍),这里也再一次加速了程序运行。但是这个优化随机而来的一个问题是:有可能每次分割都不是最佳分割。4 .使用了C+
32、11的thread库进行了并行实现,开出4个线程,程序相比单线程加速了4倍。七.并行实现C+11thread库创建线程,为每个线程赋予独立的数据容器,并将随机森林分成等量的4部分(因为我使用的是4个线程)。即,每个线程中执行的函数承担1/4规模的随机森林的构造,实现代码如下:thrvthread1(mainlnThread,transformOutPerTimeTl,traininPerTimisTl,transformTestOutTl.&Treel);three:thread2(mainlnThread,transforrniOutPeifTimeT2ltraininPerTimeT2,transformTestOutT2,&Tree2);threadthread3(mainlnThread,transfomniOutPerTimeTS,tramInPerTinriieT3KtransformTestOutTB,aTree3);threadthrwd4(m3in|nThreaiditran$formOutPeirTiiTieT4itrainIinP
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 皮草大衣销售话术
- 消防安全公共教育平台
- 光明联想电气安全培训课件
- 2025-2026学年广东省学八年级(上)期中语文试卷
- 光伏网络安全培训
- 2025-2026学年统编版八年级道德与法治上学期期末常考题之走近社会生活
- 留学生经济考试题及答案
- 口腔验收考试题目及答案
- 2024译林版四年级英语上册Unit 7 Seasons每课时教学设计汇编(含三个教学设计)
- 先进科学技术
- 【化 学】金属活动性顺序的验证与探究专项训练-2024-2025学年九年级化学人教版(2024)下册
- 2023特斯拉企业文化手册
- 新疆克拉玛依市(2024年-2025年小学六年级语文)统编版期末考试(上学期)试卷及答案
- 以工代赈社会经济效益分析
- 华中农业大学《管理学基本原理》2023-2024学年第一学期期末试卷
- KTV行业营销工作计划
- 2024年WPS计算机二级考试题库350题(含答案)
- 《文创产品策划运营人员要求》征求意见稿
- 2022年下半年教师资格证考试《高中生物》题(题目及答案解析)
- 国家开放大学《合同法》章节测试参考答案
- 北京市丰台区2023-2024学年六年级上学期期末英语试题
评论
0/150
提交评论