【问题标题】:Using a weka decision tree classifier without the whole weka library?在没有整个 weka 库的情况下使用 weka 决策树分类器?
【发布时间】:2015-07-01 19:47:10
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: export libraries classification weka labeling


    【解决方案1】:

    没有独立的库可以满足您的需求。您可以删除 Weka 中不需要的所有部分并将其打包到库中。

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

    【讨论】:

    • 好吧,weka allready 已经有一个选项来生成 java 代码,(它非常神秘,它有很多像这样命名的方法 N2fd956ad0(Object []i))但它似乎需要很多weka 库中的其他类。我会看看我是否可以为此编写一个脚本,如果成功,我会公开它。谢谢。
    【解决方案2】:

    在关注了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[])方法;
    • 返回值将是一个浮点值;
    • 返回值在 cmets 中解释,就在返回命令旁边;
    • 参数没有验证,所以要注意输入的顺序(这部分是由 weka 依赖部分完成的);
    • 顺序是 arff 文件中定义的顺序。

    【讨论】:

      【解决方案3】:

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

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

      您需要包含在 Android 应用中的代码仅包含三个类:具有生成模型的类 + 两个用于进行分类的类。

      【讨论】:

        猜你喜欢
        • 2015-02-06
        • 2014-11-23
        • 2017-01-25
        • 2021-05-16
        • 2020-08-25
        • 2016-09-02
        • 2021-04-30
        • 2023-01-09
        • 2014-11-25
        相关资源
        最近更新 更多