0

我已经为我的实例训练了一个分类器,现在想将它导出到一个 Android 应用程序,其中 Weka 库将不可用。

不适合简单地在 Android 应用程序中添加 Weka 库,因为它的大小(6.5 Mb)。

有没有其他方法可以使用我的分类器来评估和标记其他未标记的实例?是否有专门为此设计的较小的独立库?

当然,最终我可以编写自己的库来解释 Weka 的输出模型,但在我看来,这样的解决方案已经存在,这似乎是合乎逻辑的。(虽然它以某种方式逃脱了我)

4

3 回答 3

2

没有独立的库可以做你想做的事。您可以删除所有不需要的 Weka 部分并将其打包到库中。

在您的特定情况下,最简单的做法可能是采用 Weka 学习的决策树并将其直接放入一系列if...else语句中的代码中。您甚至可以编写一个脚本,获取决策树的(图形)输出并为您编写该代码。

于 2013-01-24T18:32:14.840 回答
1

在关注了 weka 的输出模型之后,我注意到通过使用以 Java 类形式生成树的选项,我可以将它与 weka 库分开使用。

您可以删除生成的 WekaWrapper 并仅保留内部类,这是树的基本实现:

该类看起来像这样:

public class WekaWrapper
  extends Classifier {

  /**
   * Returns only the toString() method.
   *
   * @return a string describing the classifier
   */
  public String globalInfo() {
    return toString();
  }

  /**
   * Returns the capabilities of this classifier.
   *
   * @return the capabilities
   */
  public Capabilities getCapabilities() {
    weka.core.Capabilities result = new weka.core.Capabilities(this);

    result.enable(weka.core.Capabilities.Capability.NOMINAL_ATTRIBUTES);
    result.enable(weka.core.Capabilities.Capability.NOMINAL_CLASS);
    result.enable(weka.core.Capabilities.Capability.MISSING_CLASS_VALUES);

    result.setMinimumNumberInstances(0);

    return result;
  }

  /**
   * only checks the data against its capabilities.
   *
   * @param i the training data
   */
  public void buildClassifier(Instances i) throws Exception {
    // can classifier handle the data?
    getCapabilities().testWithFail(i);
  }

  /**
   * Classifies the given instance.
   *
   * @param i the instance to classify
   * @return the classification result
   */
  public double classifyInstance(Instance i) throws Exception {
    Object[] s = new Object[i.numAttributes()];

    for (int j = 0; j < s.length; j++) {
      if (!i.isMissing(j)) {
        if (i.attribute(j).isNominal())
          s[j] = new String(i.stringValue(j));
        else if (i.attribute(j).isNumeric())
          s[j] = new Double(i.value(j));
      }
    }

    // set class value to missing
    s[i.classIndex()] = null;

    return WekaClassifier.classify(s);
  }

  /**
   * Returns the revision string.
   * 
   * @return        the revision
   */
  public String getRevision() {
    return RevisionUtils.extract("1.0");
  }

  /**
   * Returns only the classnames and what classifier it is based on.
   *
   * @return a short description
   */
  public String toString() {
    return "Auto-generated classifier wrapper, based on weka.classifiers.trees.Id3 (generated with Weka 3.6.9).\n" + this.getClass().getName() + "/WekaClassifier";
  }

  /**
   * Runs the classfier from commandline.
   *
   * @param args the commandline arguments
   */
  public static void main(String args[]) {
    runClassifier(new WekaWrapper(), args);
  }
}

class WekaClassifier {
  private static void checkMissing(Object[] i, int index) {
    if (i[index] == null)
      throw new IllegalArgumentException("Null values are not allowed!");
  }

  public static double classify(Object[] i) {
    return node0(i);
  }

  protected static double node0(Object[] i) {
    return 0.0; // unacc
  }
}

所以,是的,事实上你可以很容易地做到这一点。要记住的事情:

  • 对实例进行分类,调用classify(Object[])方法;
  • 返回值将是一个浮点值;
  • 返回值在注释中解释,就在返回命令旁边;
  • 参数没有验证,所以要小心输入它们的顺序(这部分是由 weka 依赖部分完成的);
  • 顺序是 arff 文件中定义的顺序。
于 2013-01-25T21:47:01.967 回答
0

如果您想运行 RandomForests,您可以使用我编写的一个小脚本,它将 WEKA 的 RandomForest 分类器的 -printTrees 选项的输出转换为 Java 源代码。

http://pielot.org/2015/06/exporting-randomforest-models-to-java-source-code/

您需要包含到您的 Android 应用程序中的代码将仅包含三个类:具有生成模型的类 + 两个使分类工作的类。

于 2015-07-01T11:47:10.200 回答