WEKA:使用反序列化模型对实例进行分类

时间:2014-02-05 15:57:19

标签: java weka ml

我使用了Weka Explorer:

  • 加载了arff文件
  • 应用StringToWordVector过滤器
  • 选择IBk作为最佳分类器
  • 生成/保存my_model.model二进制文件

在我的java代码中,我反模型化了模型:

    URL curl = ClassUtility.findClasspathResource( "models/my_model.model" );
    final Classifier cls = (Classifier) weka.core.SerializationHelper.read( curl.openConnection().getInputStream() );

现在,我有分类器,但我需要以某种方式获取有关过滤器的信息。我得到的是:如何通过我的反序列化模型准备要分类的实例(如何在分类之前应用过滤器) - (我必须分类的原始实例有一个带有标记的字段文本。过滤器应该将其转换为新的属性列表)

我甚至尝试使用FilteredClassifier,我将分类器设置为反序列化,并将过滤器设置为手动创建的StringToWordVector实例

    final StringToWordVector filter = new StringToWordVector();
    filter.setOptions(new String[]{"-C", "-P x_", "-L"});
    FilteredClassifier fcls = new FilteredClassifier();
    fcls.setFilter(filter);
    fcls.setClassifier(cls);

以上也不起作用。它引发了异常:

线程“main”中的异常java.lang.NullPointerException:未定义输出实例格式

我想避免的是在java代码中进行培训。它可能非常慢,前景是我可能有多个分类器来训练(不同的算法),我希望我的应用程序能够快速启动。

2 个答案:

答案 0 :(得分:1)

您的问题是您的模型对过滤器对数据的处理方式一无所知。 StringToWordVector过滤器会更改数据,但会根据输入(训练)数据进行更改。在此转换数据集上训练的模型仅适用于经历完全相同转换的数据。为了保证这一点,过滤器需要成为模型的一部分。

使用FilteredClassifier是正确的想法,但您必须从头开始使用它:

  • 加载ARFF文件
  • 选择FilteredClassifier作为分类器
  • 选择StringToWordVector作为过滤器
  • 选择IBk作为FilteredClassifier
  • 的分类器
  • 生成/保存模型到my_model.binary

经过训练和序列化的模型还将包含初始化过滤器,包括有关如何转换数据的信息。

答案 1 :(得分:1)

另一种方法是对测试数据使用与训练数据相同的过滤器。我分析地描述了这个过程。在您的情况下,您只需在加载序列化分类器后按照步骤操作。

  • 创建您的培训文件(例如training.arff)
  • 从培训文件创建实例。 Instances trainingData = ..
  • 使用 StringToWordVector 将字符串属性转换为数字表示形式:

示例代码:

    StringToWordVector() filter = new StringToWordVector(); 
    filter.setWordsToKeep(1000000);
    if(useIdf){
        filter.setIDFTransform(true);
    }
    filter.setTFTransform(true);
    filter.setLowerCaseTokens(true);
    filter.setOutputWordCounts(true);
    filter.setMinTermFreq(minTermFreq);
    filter.setNormalizeDocLength(new SelectedTag(StringToWordVector.FILTER_NORMALIZE_ALL,StringToWordVector.TAGS_FILTER));
    NGramTokenizer t = new NGramTokenizer();
    t.setNGramMaxSize(maxGrams);
    t.setNGramMinSize(minGrams);    
    filter.setTokenizer(t);  
    WordsFromFile stopwords = new WordsFromFile();
    stopwords.setStopwords(new File("data/stopwords/stopwords.txt"));
    filter.setStopwordsHandler(stopwords);
    if (useStemmer){
        Stemmer s = new /*Iterated*/LovinsStemmer();
        filter.setStemmer(s);
    }
    filter.setInputFormat(trainingData);
  • 将过滤器应用于trainingData:trainingData = Filter.useFilter(trainingData, filter);

  • 选择分类器以创建模型

LibLinear分类器的示例代码

        Classifier cls = null;
        LibLINEAR liblinear = new LibLINEAR();
        liblinear.setSVMType(new SelectedTag(0, LibLINEAR.TAGS_SVMTYPE));
        liblinear.setProbabilityEstimates(true);
        // liblinear.setBias(1); // default value
        cls = liblinear;
        cls.buildClassifier(trainingData);
  • 保存模型

示例代码

    System.out.println("Saving the model...");
    ObjectOutputStream oos;
    oos = new ObjectOutputStream(new FileOutputStream(path+"mymodel.model"));
    oos.writeObject(cls);
    oos.flush();
    oos.close();
  • 创建测试文件(例如testing.arff)

  • 从培训文件创建实例:Instances testingData=...

  • 加载分类器

示例代码

Classifier myCls = (Classifier) weka.core.SerializationHelper.read(path+"mymodel.model");
  • 使用与上面相同的StringToWordVector过滤器或为testingData创建一个新过滤器,但请记住对此命令使用trainingData:filter.setInputFormat(trainingData); 这将保留训练集的格式,不会添加不在训练集中的单词。

  • 将过滤器应用于testingData:testingData = Filter.useFilter(testingData, filter);

  • 分类<!/ p>

示例代码

 for (int j = 0; j < testingData.numInstances(); j++) {
    double res = myCls.classifyInstance(testingData.get(j));
 }