使用 LibLinear 進行文字分類

  • 從 .arff 檔案建立培訓例項
private static Instances getDataFromFile(String path) throws Exception{

    DataSource source = new DataSource(path);
    Instances data = source.getDataSet();
    
    if (data.classIndex() == -1){
        data.setClassIndex(data.numAttributes()-1);
        //last attribute as class index
    }
    
    return data;    
}
Instances trainingData = getDataFromFile(pathToArffFile);
  • 使用 StringToWordVector 將字串屬性轉換為數字表示形式:

    *此過濾器的重要功能:

    1. tf-idf 表示
    2. 詞幹
    3. 小寫的
    4. 停用詞
    5. n-gram 表示*
    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 分類器

    1. 下面的 SVMType 0 對應於 L2 正則化邏輯迴歸
    2. 設定 setProbabilityEstimates(true) 以列印輸出 probalities
        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();
  • .arff 檔案建立測試例項
 Instances trainingData = getDataFromFile(pathToArffFile);
  • 載入分類器
Classifier myCls = (Classifier) weka.core.SerializationHelper.read(path+"mymodel.model");
  • 使用與上面相同的 StringToWordVector 過濾器或為 testingData 建立一個新過濾器,但請記住使用 trainingData 來執行此命令:filter.setInputFormat(trainingData); 這將使訓練和測試例項相容。或者你可以使用 InputMappedClassifier

  • 將過濾器應用於 testingData:testingData = Filter.useFilter(testingData, filter);

  • 分類!

    1.獲取測試集中每個例項的類值

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

res 是一個 double 值,對應於 .arff 檔案中定義的標稱類。要獲得名義上的類使用:testintData.classAttribute().value((int)res)

2.獲取每個例項的概率分佈

 for (int j = 0; j < testingData.numInstances(); j++) {
    double[] dist = first.distributionForInstance(testInstances.get(j));
 }

dist 是一個雙陣列,包含 .arff 檔案中定義的每個類的概率

注意。分類器應支援概率分佈,並使用:myClassifier.setProbabilityEstimates(true); 啟用它們