我已经为我的实例训练了一个分类器,现在想将其导出到 Android 应用程序,其中 Weka 库将不可用。
在Android应用程序中简单地添加Weka库是不合适的,因为它的大小(6.5 Mb)。
还有其他方法可以使用分类器来评估和标记其他未标记的实例吗?是否有任何较小的独立图书馆专门为此设计?
当然,我最终可以编写自己的库来解释 Weka 的输出模型,但在我看来,这样的解决方案已经存在似乎是合乎逻辑的。(虽然它以某种方式逃脱了我)
没有独立的库可以做你想做的事。您可以删除 Weka 中所有不需要的部分,并将其打包到库中。
在您的特定情况下,最简单的方法可能是将 Weka 学习的决策树直接放入一系列 if...else
语句中的代码中。您甚至可以编写一个脚本,该脚本获取决策树的(图形)输出并为您编写该代码。
在更加关注 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[]) 方法;
- 返回值将是浮点值;
- 返回值在 return 命令旁边的注释中进行了说明;
- 参数没有验证,因此请注意输入它们的顺序(这部分由 weka 依赖部分完成);
- 顺序是 ARFF 文件中定义的顺序。
你可以使用我写的一个小脚本,将RandomForest分类器的WEKA的-printTrees选项的输出转换为Java源代码。
http://pielot.org/2015/06/exporting-randomforest-models-to-java-source-code/
您需要包含在 Android 应用中的代码将仅包含三个类:具有生成模型的类 + 两个用于进行分类的类。