mahout决策树之Partial Implementation源码分析 part2

xiaoxiao2021-03-01  18

决策树Partial Implementation源码的第二部分为:BuildForest,其源码所在位置为:MAHOUT_HOME/example/src/main/java/org/apache/mahout/classifier/df/mapreduce/BuildForest.java,现对其进行简要分析:

打开源码可以看到,BuildForest有如下四个步骤:

(1)创建一个DecisionTreeBuilder对象,并设置四个参数:

DecisionTreeBuilder treeBuilder = new DecisionTreeBuilder(); treeBuilder.setM(m); treeBuilder.setComplemented(complemented); treeBuilder.setMinSplitNum(minSplitNum); treeBuilder.setMinVarianceProportion(minVarianceProportion)(2)新建Builder接口,此处因为是并行参数(-p)所以使用PartialBuilder实现类:

Builder forestBuilder = new PartialBuilder(treeBuilder, dataPath, datasetPath, seed, getConf());初始化的ParitalBuilder类的参数为:treeBuilder(DecisionTreeBuilder),这个参数只设置了四个参数,其他都未设置;

dataPath:输入训练数据的路径;datasetPath:对训练数据的描述文件的路径;seed:初始种子(暂时未深究);

getConf():各种配置参数(个人猜测);

(3)创建森林,设置树的个数:

DecisionForest forest = forestBuilder.build(nbTrees);nbTrees表示要创建树的个数;

(4)把上面创建的森林写入HDFS:

DFUtils.storeWritable(getConf(), forestPath, forest);上面四个步骤是BuildForest的四个主要操作,其他都是一些参数设置之类的辅助操作。对于上面四个步骤,其中第三歩,调用build方法最为复杂,现简要分析如下:

Builder是抽象类,定义了build非抽象方法,实现类PartialBuilder不用覆写此方法,而直接调用其父类(Builder)的build方法,Builder的build方法可分为如下几步:

<1>设置参数,包括seed,nbTrees,treeBuilder:

setRandomSeed(conf, seed); setNbTrees(conf, nbTrees); setTreeBuilder(conf, treeBuilder);<2>把训练数据的描述文件放入内存中(这样理解是否?个人理解就是类似全局变量的作用):

DistributedCache.addCacheFile(datasetPath.toUri(), conf);<3>新建Job任务,名字为‘decision forest builder’:

Job job = new Job(conf, "decision forest builder");<4>对新建的job进行配置:

configureJob(job);<5>提交任务,等待结果:

runJob(job){ return job.waitForCompletion(true); }<6>调用parseOutput方法得到森林(forest),删除输出文件,返回结果:

DecisionForest forest = parseOutput(job); HadoopUtil.delete(conf, outputPath); return forest;这里为什么要删除outputPath呢?下面再说。

其中第<4>、<6>步在Builder中都是抽象方法,由其实现类进行覆写实现,在PartialBuilder中的configureJob()和parseOutput()如下:

cofigureJob():设置这个job的相关参数,Mapper为Step1Mapper,输出Key和Value类型分别为:TreeID、MapredOutput,输入文件为dataPath,输出文件为outputPath;

FileInputFormat.setInputPaths(job, getDataPath()); FileOutputFormat.setOutputPath(job, getOutputPath(conf)); job.setOutputKeyClass(TreeID.class); job.setOutputValueClass(MapredOutput.class); job.setMapperClass(Step1Mapper.class);这里输出文件的路径设置为outputPath,所以在上面第<6>步中要删除这个文件;

parseOutput():其操作如下:

Node[] trees = new Node[numTrees]; processOutput(job, outputPath, keys, trees); return new DecisionForest(Arrays.asList(trees));processOutput():操作如下:

for (Pair<TreeID,MapredOutput> record : new SequenceFileIterable<TreeID, MapredOutput>(path, conf)) { MapredOutput value = record.getSecond(); if (trees != null) { trees[index] = value.getTree(); } index++; }processOutput的操作也就是把输出文件的内容全部读入trees(Node[])中,然后以trees为参数建立一个DecisionForest返回;

DecisionForest返回过程如下:DecisionForest-->processOutput(PartialBuilder)-->parseOutput(PartialBuilder)-->build(PartialBuilder);

在build方法中的<3>、<4>、<5>步是整个BuilderForest的关键所在,所涉及到的类目前可以很明显的看到的有:TreeID(map输出Key类型)、MapredOutput(map输出Value类型)、Step1Mapper(job的Mapper操作);

<3><4><5>步下次再看。。

分享,快乐,成长

转载请注明出处:http://blog.csdn.net/fansy1990

转载请注明原文地址: https://www.6miu.com/read-3200030.html

最新回复(0)