我挺好奇mahout是怎样分布式建立一个随机森林的,所以特意看看它的BuildForest源码,看看里边的mapreduce是怎样实现的。
还有个问题也挺让我好奇的,就是随机森林是怎么保存的呢?
我看的是0.9版本的mahout。
首先想想随机森林的可并行性在哪里?如果是我来做并行,会怎么做呢?
因为随机森林是由很多决策树组成,而这些决策树建立的时候相互之间是不影响的,所以建树这个过程便是可以并行化的。
接着考虑数据问题,以前我用weka编程,一个1G多的数据全部用来做训练,然后就会报内存溢出,所以在大数据下,这个问题该怎么解决呢?
数据太大,一般都会切分成很多block,放在不同的datanode里边存储,那么是要把所有数据都拿到然后训练还是该怎么做呢?
看看mahout是怎么解决这个问题的吧!
BuildForest类
首先从BuildForest类开始,这个类在package org.apache.mahout.classifier.df.mapreduce里边,
在mahout-distribution-0.9\examples\src\main\java\org\apache\mahout\classifier\df\mapreduce文件夹里边。
这个类定义的参数如下,依次为:
- dataPath,数据集路径
- datasetPath,虽然名为数据集,但实际上是描述数据集的文件,也即描述数据各个属性以及label属性
- outputPath,生成的随机森林的保存路径
- m,生成决策树的时候每次随机选择的参数个数
- complemented,生成的树是否为完全树么
- minSplitNum,分类树判断一个节点是否需要继续分裂下去时使用,如果一个节点里边属性数目小于minSplitNum,那么就不再分裂,设置为叶子节点
- minVarianceProportion,同上,不过是回归树使用
- nbTrees,森林的决策树数目
- seed,随机种子
- isPartial,我觉得这个挺有意思的,使用部分数据,怎么选择部分呢?剩下的部分呢?
private Path dataPath;
private Path datasetPath;
private Path outputPath;
private Integer m; // Number of variables to select at each tree-node
private boolean complemented; // tree is complemented
private Integer minSplitNum; // minimum number for split
private Double minVarianceProportion; // minimum proportion of the total variance for split
private int nbTrees; // Number of trees to grow
private Long seed; // Random seed
private boolean isPartial; // use partial data implementation
这个类继续Configured类实现Tool接口,所以需要重载run方法。
run方法首先处理输入参数,这一段不是我关注的,所以不管它啦,
读取参数之后,便运行了一个buildForest函数。
buildForest函数
// make sure the output path does not exist
FileSystem ofs = outputPath.getFileSystem(getConf());
if (ofs.exists(outputPath)) {
log.error("Output path already exists");
return;
}
然后是决策树生成器的创建,并根据输入设置它的参数。
DecisionTreeBuilder treeBuilder = new DecisionTreeBuilder();
if (m != null) {
treeBuilder.setM(m);
}
treeBuilder.setComplemented(complemented);
if (minSplitNum != null) {
treeBuilder.setMinSplitNum(minSplitNum);
}
if (minVarianceProportion != null) {
treeBuilder.setMinVarianceProportion(minVarianceProportion);
}
接着是森林生成器的创建,依然是根据输入设置参数。
Builder forestBuilder;
if (isPartial) {
log.info("Partial Mapred implementation");
forestBuilder = new PartialBuilder(treeBuilder, dataPath, datasetPath, seed, getConf());
} else {
log.info("InMem Mapred implementation");
forestBuilder = new InMemBuilder(treeBuilder, dataPath, datasetPath, seed, getConf());
}
forestBuilder.setOutputDirName(outputPath.getName());
最后就是生成森林以及保存森林了。
DecisionForest forest = forestBuilder.build(nbTrees);
// store the decision forest in the output path
Path forestPath = new Path(outputPath, "forest.seq");
log.info("Storing the forest in: {}", forestPath);
DFUtils.storeWritable(getConf(), forestPath, forest);
forestBuild
- 数据不大的话,把所有数据都放到内存中,然后用所有数据训练决策树
- 数据很大的话,把Mapper所在节点的这部分数据取出来用作训练,其它数据不管