Weka 3.7.12源码学习、阅读、分析(2)

以前的文章里写到过Classififer的基本做用,它是Weka中分类器都须要实现的抽象类。 html

此次的AbstractClassifier即实现了Classifier,但并无实现所有方法,所以仍为抽象类。 java

此外该类还实现了若干个接口,简要介绍以下: 数组


// Cloneable:提供了一个复制特定类下实例的方法,实现该接口需重写Object.clone app

//Serializable:保证了类的可序列化,需实现java.io.Serializable 接口 ide

//OptionHandler:对界面选项的描述 函数

//CapabilotiesHandler:查看对象的适用范围 学习

//RevisionHandler:返回修订信息 测试

//CapabilitiesIgnorer:设定或取得适用范围信息 ui

public abstract class AbstractClassifier implements Classifier, Cloneable,
                                                    Serializable, OptionHandler,
                                                    CapabilitiesHandler, RevisionHandler,
                                                    CapabilitiesIgnorer lua

//显式声明了序列化,java对象序列化不只保留一个对象的数据,并且递归保存对象引用的每一个对象的数据。序列化运行时使用一个称为 serialVersionUID 的版本号与每一个可序列化类相关联。学习自:http://blog.csdn.net/applehoney/article/details/2278086

private static final long serialVersionUID = 6502780192411755341L;

//是否在调试模式下运行

protected boolean m_Debug = false;

//是否预先检查分类器适用范围

protected boolean m_DoNotCheckCapabilities = false;

//做用:对测试实例进行分类

//参数:被分类的实例  返回值:实例被预测的分类或Utils.missingValue()(分类不成功)

//抛出异常:若是预测时发生错误

@Override
  public double classifyInstance(Instance instance) throws Exception {

//调用distributionForInstance()方法

    double[] dist = distributionForInstance(instance);
    if (dist == null) {
      throw new Exception("Null distribution predicted");
    }
    switch (instance.classAttribute().type()) {
    case Attribute.NOMINAL:
      double max = 0;
      int maxIndex = 0;

//获得最大的几率,即最可能的分类类别

      for (int i = 0; i < dist.length; i++) {
        if (dist[i] > max) {
          maxIndex = i;
          max = dist[i];
        }
      }
      if (max > 0) {
        return maxIndex;
      } else {
        return Utils.missingValue();
      }
    case Attribute.NUMERIC:
    case Attribute.DATE:
      return dist[0];//dist[0]中放置了分类信息
    default:
      return Utils.missingValue();
    }
  }

//做用:预测实例的类关系

//返回值:一个包含测试实例在每个可能分类上的分类几率的数组或者一个数值型的预测

//抛出异常:若是几率不能被成功计算

@Override
  public double[] distributionForInstance(Instance instance) throws Exception {

    double[] dist = new double[instance.numClasses()];//获得instance类标号的数目并做为数组长度
    switch (instance.classAttribute().type()) {//以整形来判断属性的类型
    case Attribute.NOMINAL://枚举型
      double classification = classifyInstance(instance);//返回instance的分类
      if (Utils.isMissingValue(classification)) {
        return dist;//全0数组
      } else {
        dist[(int) classification] = 1.0;//最可能分类位为1,其他为0的数组
      }
      return dist;
    case Attribute.NUMERIC:
    case Attribute.DATE:
      dist[0] = classifyInstance(instance);//数字或日期型,直接将分类号放置在数组0位
      return dist;
    default:
      return dist;
    }
  }

//设立一个自定义的分类器,给出名字及操做名称

//参数:分类器名称

//参数:操做名称

//返回:可使用的分类器

//抛出异常:分类器名称非法,或操做名格式不符不能被接收

public static Classifier forName(String classifierName, String[] options)
    throws Exception {

    return ((AbstractClassifier) Utils.forName(Classifier.class,
      classifierName, options));
  }

//使用序列化对分类器进行深拷贝(深、浅拷贝的区别学习自http://www.cnblogs.com/haiyang1985/archive/2009/01/13/1375017.html

//参数model:将要拷贝的分类器

//返回:特定分类器的深拷贝

//抛出异常:若是发生错误

public static Classifier makeCopy(Classifier model) throws Exception {

    return (Classifier) new SerializedObject(model).getObject();
  }

//做用:用序列化的方法对给定的分类器进行给定数量的深拷贝。

//参数 model:被拷贝的分类器

//参数 num:拷贝的数量

//返回:分类器的数组

//异常:错误发生时

  public static Classifier[] makeCopies(Classifier model, int num)
    throws Exception {

    if (model == null) {
      throw new Exception("No model classifier set");
    }
    Classifier[] classifiers = new Classifier[num];
    SerializedObject so = new SerializedObject(model);
    for (int i = 0; i < classifiers.length; i++) {
      classifiers[i] = (Classifier) so.getObject();
    }
    return classifiers;
  }

//做用:返回对操做描述的枚举

//返回:可用操做的枚举

@Override
  public Enumeration<Option> listOptions() {

    Vector<Option> newVector = new Vector<Option>(2);

    newVector.addElement(new Option(
      "\tIf set, classifier is run in debug mode and\n"
        + "\tmay output additional info to the console", "output-debug-info",
      0, "-output-debug-info"));
    newVector
      .addElement(new Option(
        "\tIf set, classifier capabilities are not checked before classifier is built\n"
          + "\t(use with caution).", "-do-not-check-capabilities", 0,
        "-do-not-check-capabilities"));

    return newVector.elements();
  }

//做用:依照给定的操做运行分类实例

//参数:分类器名

//参数:操做名称

public static void runClassifier(Classifier classifier, String[] options) {
    try {
      System.out.println(Evaluation.evaluateModel(classifier, options));//输出验证后的结果
    } catch (Exception e) {
      if (((e.getMessage() != null) && (e.getMessage().indexOf(
        "General options") == -1))
        || (e.getMessage() == null)) {
        e.printStackTrace();
      } else {
        System.err.println(e.getMessage());
      }
    }
  }
}

public static String evaluateModel()函数比较复杂,含有大量的判断语句,涉及到模型验证的许多参数,在这里咱们暂且搁置。

AbstractClassifier类中其他的是一些简单的getter和setter,还有一些提示语句,就不列出来了。虽然尚未接触到具体的分类功能,程序已经变得很是复杂,学习的过程当中,也不能忘了向Weka的做者们致敬,感谢大家无私的付出!

相关文章
相关标签/搜索