2014-12-30 3 views
1

Я пытаюсь построить текстовый классификатор с помощью ВЕКА, но вероятности с distributionForInstance классов являются 1.0 в одном и 0.0 во всех остальных случаях, так что classifyInstance всегда возвращается тот же класс, что и прогнозирование. Что-то в тренировке работает неправильно.текст классификатор с WEKA: как правильно дрессировать вопрос классификаторов

ARFF обучение

@relation test1 

@attribute tweetmsg String 
@attribute classValues {politica,sport,musicatvcinema,infogeneriche,fattidelgiorno,statopersonale,checkin,conversazione} 

@DATA 

"Renzi Berlusconi Salvini Bersani",politica 
"Allegri insulta la terna arbitrale",sport 
"Bravo Garcia",sport 

Методы обучения

public void trainClassifier(final String INPUT_FILENAME) throws Exception 
{ 
    getTrainingDataset(INPUT_FILENAME); 

    //trainingInstances consists of feature vector of every input 

    for(Instance currentInstance : inputDataset) 
    {   
     Instance currentFeatureVector = extractFeature(currentInstance); 

     currentFeatureVector.setDataset(trainingInstances); 
     trainingInstances.add(currentFeatureVector);     
    } 

    classifier = new NaiveBayes(); 

    try { 
     //classifier training code 
     classifier.buildClassifier(trainingInstances); 

     //storing the trained classifier to a file for future use 
     weka.core.SerializationHelper.write("NaiveBayes.model",classifier); 
    } catch (Exception ex) { 
     System.out.println("Exception in training the classifier."+ex); 
    } 
} 

private Instance extractFeature(Instance inputInstance) throws Exception 
{  
    String tweet = inputInstance.stringValue(0); 
    StringTokenizer defaultTokenizer = new StringTokenizer(tweet); 
    List<String> tokens=new ArrayList<String>(); 
    while (defaultTokenizer.hasMoreTokens()) 
    { 
     String t= defaultTokenizer.nextToken(); 
     tokens.add(t); 
    } 

    Iterator<String> a = tokens.iterator(); 
    while(a.hasNext()) 
    { 
       String token=(String) a.next(); 
       String word = token.replaceAll("#",""); 
       if(featureWords.contains(word)) 
       {            
        double cont=featureMap.get(featureWords.indexOf(word))+1; 
        featureMap.put(featureWords.indexOf(word),cont); 
       } 
       else{ 
        featureWords.add(word); 
        featureMap.put(featureWords.indexOf(word), 1.0); 
       } 

    } 
    attributeList.clear(); 
    for(String featureWord : featureWords) 
    { 
     attributeList.add(new Attribute(featureWord)); 
    } 
    attributeList.add(new Attribute("Class", classValues)); 
    int indices[] = new int[featureMap.size()+1]; 
    double values[] = new double[featureMap.size()+1]; 
    int i=0; 
    for(Map.Entry<Integer,Double> entry : featureMap.entrySet()) 
    { 
     indices[i] = entry.getKey(); 
     values[i] = entry.getValue(); 
     i++; 
    } 
    indices[i] = featureWords.size(); 
    values[i] = (double)classValues.indexOf(inputInstance.stringValue(1)); 
    trainingInstances = createInstances("TRAINING_INSTANCES"); 

    return new SparseInstance(1.0,values,indices,1000000); 
} 


private void getTrainingDataset(final String INPUT_FILENAME) 
{ 
    try{ 
     ArffLoader trainingLoader = new ArffLoader(); 
     trainingLoader.setSource(new File(INPUT_FILENAME)); 
     inputDataset = trainingLoader.getDataSet(); 
    }catch(IOException ex) 
    { 
     System.out.println("Exception in getTrainingDataset Method"); 
    } 
    System.out.println("dataset "+inputDataset.numAttributes()); 
} 

private Instances createInstances(final String INSTANCES_NAME) 
{ 
    //create an Instances object with initial capacity as zero 
    Instances instances = new Instances(INSTANCES_NAME,attributeList,0); 
    //sets the class index as the last attribute 
    instances.setClassIndex(instances.numAttributes()-1); 

    return instances; 
} 

public static void main(String[] args) throws Exception 
{ 
     Classificatore wekaTutorial = new Classificatore(); 
     wekaTutorial.trainClassifier("training_set_prova_tent.arff"); 
     wekaTutorial.testClassifier("testing.arff"); 
} 

public Classificatore() 
{ 
    attributeList = new ArrayList<Attribute>(); 
    initialize(); 
}  

private void initialize() 
{ 

    featureWords= new ArrayList<String>(); 

    featureMap = new TreeMap<>(); 

    classValues= new ArrayList<String>(); 
    classValues.add("politica"); 
    classValues.add("sport"); 
    classValues.add("musicatvcinema"); 
    classValues.add("infogeneriche"); 
    classValues.add("fattidelgiorno"); 
    classValues.add("statopersonale"); 
    classValues.add("checkin"); 
    classValues.add("conversazione"); 
} 

ИСПЫТАНИЙ МЕТОДЫ

public void testClassifier(final String INPUT_FILENAME) throws Exception 
{ 
    getTrainingDataset(INPUT_FILENAME); 

    //trainingInstances consists of feature vector of every input 
    Instances testingInstances = createInstances("TESTING_INSTANCES"); 

    for(Instance currentInstance : inputDataset) 
    { 

     //extractFeature method returns the feature vector for the current input 
     Instance currentFeatureVector = extractFeature(currentInstance); 
     //Make the currentFeatureVector to be added to the trainingInstances 
     currentFeatureVector.setDataset(testingInstances); 
     testingInstances.add(currentFeatureVector); 

    } 


    try { 
     //Classifier deserialization 
     classifier = (Classifier) weka.core.SerializationHelper.read("NaiveBayes.model"); 

     //classifier testing code 
     for(Instance testInstance : testingInstances) 
     { 

      double score = classifier.classifyInstance(testInstance); 
      double[] vv= classifier.distributionForInstance(testInstance); 
      for(int k=0;k<vv.length;k++){ 
      System.out.println("distribution "+vv[k]); //this are the probabilities of the classes and as result i get 1.0 in one and 0.0 in all the others 
      } 
      System.out.println(testingInstances.attribute("Class").value((int)score)); 
     } 
    } catch (Exception ex) { 
     System.out.println("Exception in testing the classifier."+ex); 
    } 
} 

Я хочу, чтобы создать текстовый классификатор для коротких сообщений, этот код основан на этом руководстве http://preciselyconcise.com/apis_and_installations/training_a_weka_classifier_in_java.php , Проблема в том, что классификатор предсказывает неправильный класс почти для каждого сообщения в test.arff, потому что вероятности классов неверны. Training_set_prova_tent.arff имеет одинаковое количество сообщений для каждого класса. В следующем примере я использую featureWords.dat и ассоциирую 1.0 со словом, если оно присутствует в сообщении, вместо этого я хочу создать свой собственный словарь со словами, присутствующими в training_set_prova_tent, плюс слова, присутствующие в тестировании, и связывать их с каждым введите число вхождений.

PS Я знаю, что это именно то, что я могу сделать с фильтром StringToWordVector, но я не нашел примера, который бы использовал этот фильтр с двумя файлами: один для набора обучения и один для тестового набора , Так что мне легче адаптировать код, который я нашел.

Большое спасибо

+1

Я думаю, что знаю, что вы пытаетесь сделать, и я мог бы получить ответ. Но, конечно: вы хотите классифицировать твиты (короткие тексты) на несколько классов (ваши «classValues') на основе количества слов, правильно? – Sentry

+0

Правильно !! Я действительно надеюсь, что вы сможете мне помочь – user273686

+0

Можете ли вы добавить код для 'getTrainingDataset (...)'? Я не могу заставить код работать без него. Также: Не могли бы вы перефразировать текст после вашего примера кода? Я не понимаю его полностью и могут быть важные детали. – Sentry

ответ

1

Похоже, вы изменили код с website you referenced в некоторых ключевых моментов, но не в хорошем смысле. Я попытаюсь создать то, что вы пытаетесь сделать, и какие ошибки я нашел.

То, что вы (вероятно) хотел сделать в extractFeature является

  • Split каждый твит в слова (разметить)
  • Подсчитать количество вхождений этих слов
  • Создать вектор признаков, представляющий эти слова отсчеты плюс класс

Что вы упускать из виду в этом методе является

  1. Вы никогда не сбрасываете featureMap. Линия

    Map<Integer,Double> featureMap = new TreeMap<>(); 
    

    первоначально был в начале extractFeatures, но вы переместили его initialize. Это означает, что вы всегда добавляете количество слов, но никогда не сбрасываете их. Для каждого нового твита ваше количество слов также включает в себя количество слов всех предыдущих твитов. Я уверен, что это не то, что вы хотели.

  2. Вы не инициализируете featureWords словами, которые вы хотите использовать как функции. Да, вы создаете пустой список, но вы заполняете его итерационно каждым твитом.Первоначальный код инициализировал его один раз в методе initialize и после этого он не изменился. Есть две проблемы:

    • С каждым новым твитом добавляются новые функции (слова), поэтому ваш вектор-функция растет с каждым твитом. Это не будет такой большой проблемой (SparseInstance), но это означает, что
    • Ваш атрибут class всегда находится в другом месте. Эти две строки работают для исходного кода, потому что featureWords.size() в основном является константой, но в вашем коде метка класса будет указана в индексе 5, затем 8, затем 12 и т. Д., Но она должна быть одинаковой для каждого экземпляра ,
    indices[i] = featureWords.size(); 
    values[i] = (double) classValues.indexOf(inputInstance.stringValue(1)); 
    
  3. Это также проявляется в том, что вы строите новый attributeList с каждым новым чирикать, а только один раз в initialize, что это плохо для уже объяснил причины.

Может быть больше материала, но - как есть - ваш код является довольно нефиксируемым. То, что вы хотите, намного ближе к исходному коду учебника, который вы изменили, чем ваша версия.

Кроме того, вы должны смотреть в StringToWordVector потому что кажется, что это именно то, что вы хотите сделать:

Преобразует строки атрибутов в набор атрибутов, представляющих вхождение слова (в зависимости от Tokenizer) информацию из текст, содержащийся в строках. Набор слов (атрибутов) определяется первой периодической фильтрацией (обычно данными обучения).

+0

Большое спасибо, ваше объяснение очень хорошее и ясное..OK, поэтому я попытаюсь использовать StringToWordVector для создания моего кода. еще раз спасибо – user273686

Смежные вопросы