2025年机器学习实战随机森林算法深度解析与应用_第1页
2025年机器学习实战随机森林算法深度解析与应用_第2页
2025年机器学习实战随机森林算法深度解析与应用_第3页
2025年机器学习实战随机森林算法深度解析与应用_第4页
2025年机器学习实战随机森林算法深度解析与应用_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

随机森林试验汇报输入:训练数据集D,停止训练条件A,对于每一个可能的划分值a,根据大于a及小于等于a将训练数据集分成D1,D2两(2)在所有可能特征A以及其所有可能划分点a中,选择gini系数最小的特征及切分值,将D1和D2分配到左右两个子节点去。(3)对左右节点分别递归的调用(1),(2),直到满足一定条件为止。RF在每次构造一棵决策树时,先随机的有放回的从训练集中抽取(60%)或n(sizeof将一种N分类问题转化为N个二分类问题。转化措施是:构造N棵二叉拟合树,这里假设N为26,然后我们给N棵二叉树依次标号为1,2,3...26。1号树的成果对应于该条记录是不是属于第一类,是则输出1,否则输出0.2号树的成果对应于该条记录是不是属于第二类,是则1否则0,依此类推。这样,我们的26棵二叉树的成果就对应了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个索引做与否判断的二分类树视为一种整体,在多线程的环境下,2.将训练集分割为输入trainIn,输出trainOut[sampleln,transformSampleOut]=TakeSample(trai//CartTree数组寄存着26棵二分类树CartTree[category]=TrainCartTree(sampleln,transftransformTestOut[i1][category]+=predict(CartTree[category],tes6.遍历transformTrainOut[],将其每一行的最大值的下标作为该行记录的索引值。1.决策树在这里,我们每一次26分类是由26棵CART共同完毕的,CART的costfun2.随机森林a.随机森林每次循环的训练集采样为原训练集的0.5.b.对于森林中每一棵决策树每一次分割点的选用,对属性进行了打乱抽样,抽样数为25,即每次分割只在25个属性中寻找最合适的值。并且对于每个选用的属性,我们进行了行采样。即假如这个属性所拥有的属性值数不小于30,我们选用其中30个作为分割候选,假如不不小于30,则所有纳入分割候选。五.代码详解1.训练集/测试集的读入a.在dataDefine.h中定义了:训练集记录条数transetNum测试集记录条数testsetNum分类类型数typesNum而在main.cpp中,我们申明了全局变量doubletestin[testsetNum]{numparadoubletestOut{testsetNuml;trainIn用于装载训练集输入,trainOut用于装载训练集的输出(这里trainOut是二维数组是出于模型假如泛化,那么输出值不一定只有一种的状况,在本次试验中并未派上什么真正用场,可以将trainOut看作一种一般一维数组)。trainID用于装载训练集中每一行的第一列ID号。testIn,testID则对应测试集的输入和ID号。这里注意,没有testOut的原因是测试集的成果理论上应当是不存在的。然后通过自己编写的读入函数读入测试集合训练集,这个函数将分别装载我们在前面提到的trainIn、trainOut、trainID、testIn、testID。这个函数使用的fstream逐行读入的措施,这里不做详述。2.训练集输出转化为对应的26维01数组transformOut[typesNum]在dataDefine.h中,我们定义了分类类别数typesNum:WdefinetypesNum26//26类型数量在main.cpp中,我们定义了全局变量transformOut[typesNum]这里的transformOut是用于储存将trainOut每行的值映射为一行对应的26维01序列后所这里面的对应关系是:例如trainOut[10]中的值是13那么transformOut[10][13]=1,transformOut[10][除13外其他列]=0;假如值是14,那么14列为1,其他列为0,行号代表的是它们对应的是第几条记录:trainOut[10]和transformOut[10]都表达的是第10行的分类值为某个值,只是体现方式不一样。前者用数字表达,后者将对应下标的值置1表达。voidindexTransform(inttransformreslltypesNum+1),doubleogresl[1)://将原始输出转化为转化型输出在在main.cpp中,我们构建了doubletrainInPerTime[perTimeNum][numparadoubletrainInPerTimeT¹[perTimeNum][numdoubletrainInPerTimeT2[perTimeNum][numparamedoubletrainInPerTimeT3[perTimeNum][numparametres-2];doubletrainInPerTimeT4[perTimeNum][numparametres-2];inttransformOutPerTimeT¹[perTimeinttransformOutPerTimeT2[inttransformOutinttransformOutdoubletransformTestOutT¹[testsetNum][typesNum+1]={0};doubletransformTestOutT2[testsetNum][typesNum+1]=(0);doubletransformTestOutT3[testsetNum][typesNum+1]=(0);TransformOutPerTime代表的是与trainlnperTime对应的转换输出transformtestOut是承接本支线程的所有CART树的决策值之和的构造,这与算法思绪是对应的,我们我们可以看出,这几种变量都是只有最终的TX有区别,实际上,反复的创立相似的变量只是为了以这里使用的是C++11的<thread>库,简朴好用。每一种线程的随机森林框架定义在main.cpp的 这个函数采用循环的方式,每次循环,对训练集及对应转换输出进行打乱后采样,然后输入TRAIN(traininPerTime_,transformOutPerTime_,transformTesTRAIN(traininPerTime_,transformOutPerTime_,transformTes中进行一轮决策树的训练,这一轮训练将会生成26棵CART树,对应26个分类值。这里输入的参数Tree就是我们所用的决策树容器,这里注意,我们一种线程中只需要公用一种决策树构造即足够了.在训练完毕后,我们用累加训练成果。由于26棵CART树才能完整的等价于一棵26分类树,因此我们将构建这26棵CART树的过程当作是一种整体。这个过程由函数TRAIN(trainnPerTime_,transformOutPerTime_,transformTesTRAIN(trainnPerTime_,transformOutPerTime_,transformTes实现。它的输入依次是本轮的训练输入(通过了下采样,随机森林规定的),对应的转换训练输出,以及一种决策树容器Tree。决策树的定义我们将在下文中描述。这个函数有一种栈stack<int>trace;//用于追踪树的遍历过程,这里我们假并且有一种从1:26的循环的是一种先序的遍历次序。当循环完毕后,将会计算本轮的转换输出成果的变更://testresPerTime[i][typesN]=TputeRes(test5.每科CART树的构造CART树的数据构造如下:trainIntrainOut对应于输入该树的输入输出集,Nodes表达的是节点序列,在这里我们的树的构造使用的是数组,且树的节点间的索引是通过索引值维护的,这颗树非常紧密(假如只看NODES是看不出节点间的层级关系的)。它有如下组员函数:boolgetPartition(intindex,//doublecomputeNodeGini(intindex);//初始化树//对于每个节点的一些操作voidgetNodeAttr(vector<int>selectedColvoidcomputeNodeValue(int;getNodeSequence(node1[)本来是用来输出节点参数的,这里不做详述initialize用于初始化决策树。getNodeAttr用于得到某一节点的备选属性分割值computePerNodeGini用于计算某一节点的GINI值,这在停止节点分割时有用computeNodeValue是用于计算某一叶子节点的拟合值的。我们再说一下Nodes节点,它的构造如下Attrbutes[selectedColumns]是用于寄存候选的分割值的容器其他变量的功能见图片中的文字注释这里我们用datalndex寄存对应记录所在索引的措施取代了直接寄存记录,这里是一种巨大的改善,将程序的执行速度提高了至少10倍。在构造一棵决策树时,当train函数对应的trace栈的栈顶非空时,我们会不停的取出栈顶元素,对其操作,Index指的是节点所在的索引值,container用于寄存这个节点的左右叶子索引,由于树的构建是由外部栈维护的,因此这个container是必不可少的,在目前节点分割完毕后,我们会将这个节点的索引值出栈,假如container[0]的值不是-1,我们会将container[0].container[1]入栈。建树的对应模//树的初始化(插入头节点)完成后,正式开始决策树的构建(*Tree).getPartition(curren//判断当前节点是否成功分割下面再重点说一下函数:这个函数是单棵决策树构造的关键,调用这个函数,假如目前节点的Gini值已经为0,那么这个函数会计算目前节点的拟合值:ifif(Nodes[index]gini==0||Nodes[index]layer>=MaxLayerNfor(inti=0;i<Nodes[index].datalndex.size结束条件是gini==0|1层数等于10selectedColumns列。然后调用getNodeAttr(s,index)获取目前节点的备选分割值,这里的s是抽取的属性的列号的集合。在得到备选的属性分割值后,将进入循环,寻找最优分割点for(cursor=Nodes[index].attributes{).begin);cursor!=Nodes[index]attributeslj].end⁰;++temp_ginicomputeGini(index,6.最终止果计算在main函数中,我们将四个线程所得的transformOutT相加,最终遍历取每一行最大值的下标,即可得到最终止果。1.应用了数组+栈建树取代了一般的函数递归建树,加紧了建树速度。2.在传递每个节点的节点数据集时,使用了传递数据集的索引而非数据自身,这样做的好处是,本来假如传递一条数据需要复制617个double类型的数量,而目前只需要传递一种Int型的索引,这种快了617倍的数据集传递方式使程序运行效率提高了10倍以上。3.在每个属性中选择备选分割值的时候,采用了一种下采样的方略。即:假如该节点的数据集大小不不小于某一数值,则将这个数据集的这个属性的所有值都纳入候选分割值列表。不过假如不小于了这个阀值,则将属性所对应的列进行排序后再进行等间距采样得到样本数等于阈值的子集作为候选分割集。代码详见getPartition().这样做的好处是需要计算的分割gini值大大减少了(本人取的采样阈值时100,相比原数据集,样本空间缩小了尽30倍),这里也再一次加速了程序运行。不过这个优化随机而来的一种问题是:有也许每次分割都不是最佳分割。4.使用了C++11的<thread>库进行了并行实现,开出4个线程,程序相比单线程加速了4倍。七.并行实现C++1l<thread>库创立线程,为每个线程赋予独立的数据容器,并将随机森林提成等量的4部分(由于我使用的是4个线程)。即,每个线程中执行的函数承担1/4规模的随机森林的构造,实现代码如intmaininThread(inttransfomOutPerTimeIlypesSNum+11.doubletrainnPerTime

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论