xuanxufeng 发表于 2015-11-6 21:23:39

Mahout随机森林算法--分类无标签数据



开发环境:Intellij IDEA14 、Maven3.2、JDK1.7、Hadoop2.6 、mahout0.10
源码下载及运行参考:https://github.com/fansy1990/randomforest_classify
设计思路:
Mahout 随机森林算法(Random Forest)利用建立好的模型(BuildForest的输出结果)以及描述文件(Describe的输出结果),来对没有标签的数据进行分类。受TestForest中的CMapper的启发,其主要代码如下:

String line = value.toString();
      if (!line.isEmpty()) {
      Instance instance = converter.convert(line);
      double prediction = forest.classify(dataset, rng, instance);
      lkey.set(dataset.getLabel(instance));
      lvalue.set(Double.toString(prediction));
      context.write(lkey, lvalue);
      }

可以看到一行数据value,被赋值到line,然后通过line转换为Instance,之后就可以直接使用forest.classify函数来得到实际的类别了。当然,这里classify函数得到的是实际类别的下标,还需要进行一步转换,转换过程使用dataset.getLabelString(prediction)即可,这样就可以还原原始的类别了。
这里还有一个问题,TestForest里面的line里面是包含Label的,如果我们传入的line不包含label,那么通过converter.conver进行转换为Instance,肯定是有问题的,那怎么办呢?

这个问题可以通过自定义Converter来解决,具体如下:


package util;

import com.google.common.base.Preconditions;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.mahout.classifier.df.data.Dataset;
import org.apache.mahout.classifier.df.data.Instance;
import org.apache.mahout.math.DenseVector;

/**
* Created by Fansy on 2015/11/2.
*/
public class DataConverter {

//    private static final Pattern COMMA_SPACE = Pattern.compile("[, ]");

    private String splitter;
    private final Dataset dataset;
    public DataConverter(Dataset dataset,String splitter) {
      this.dataset = dataset;
      this.splitter=splitter;
    }
    public Instance convert(String string) {
      // all attributes (categorical, numerical, label), ignored
      // get rid of label ,the data only contains (categorical, numerical),ignored
      int nball = dataset.nbAttributes() + dataset.getIgnored().length-1;
// 把label列添加到vector中,方便直接调用forest的classify函数
      String[] tokens = string.split(splitter);
      Preconditions.checkArgument(tokens.length == nball,
                "Wrong number of attributes in the string: " + tokens.length + ". Must be " + nball);
      int nbattrs = dataset.nbAttributes();
      DenseVector vector = new DenseVector(nbattrs);
      int aId = 0;
      for (int attr = 0; attr < nball;) {
            if(dataset.getLabelId()==attr){//label 列所在下标
                vector.set(aId++,0);// 对于label列直接赋值0
            }
            if (!ArrayUtils.contains(dataset.getIgnored(), attr)) {
                String token = tokens.trim();

                if ("?".equals(token)) {
                  // missing value
                  return null;
                }
                if (dataset.isNumerical(aId)) {
                  vector.set(aId++, Double.parseDouble(token));
                } else { // CATEGORICAL
                  vector.set(aId, dataset.valueOf(aId, token));
                  aId++;
                }
                attr++;
            }
      }
      return new Instance(vector);
    }
}


这里在计算nball时,使用-1,即去掉Label这一个属性,这样我们的数据就可以通过Preconditions.checkArgument的验证了。
接着,在对line进行解析的过程中,要判断当前的id是否是Label(由于Label是在Describe的阶段指定的,所以这里还需要通过dataset.getLabelId来确定),如果是的话,那么就把vector的当前值赋值为0(当然这里赋值为任何的数值型都是可以的)。这样,等于是我们把传入的无label的数据人为的加入了一个任意指定的label,这样做的必要性是为了调用forest的classify函数。



分享,成长,快乐

脚踏实地,专注

转载请注明blog地址:http://blog.csdn.net/fansy1990














页: [1]
查看完整版本: Mahout随机森林算法--分类无标签数据