de.uni_koeln.spinfo.classification.zoneAnalysis.classifier.WekaClassifier.java Source code

Java tutorial

Introduction

Here is the source code for de.uni_koeln.spinfo.classification.zoneAnalysis.classifier.WekaClassifier.java

Source

/**
 * Material for the course 'Text-Engineering', University of Cologne.
 * (http://www.spinfo.phil-fak.uni-koeln.de/spinfo-textengineering.html)
 * <p/>
 * Copyright (C) 2008-2009 Fabian Steeg
 * <p/>
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3 of the License, or (at your option) any later
 * version.
 * <p/>
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * <p/>
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, see <http://www.gnu.org/licenses/>.
 */
package de.uni_koeln.spinfo.classification.zoneAnalysis.classifier;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import weka.classifiers.Classifier;
import weka.core.Attribute;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.SparseInstance;
import de.uni_koeln.spinfo.classification.core.classifier.model.Model;
import de.uni_koeln.spinfo.classification.core.data.ClassifyUnit;
import de.uni_koeln.spinfo.classification.core.data.FeatureUnitConfiguration;
import de.uni_koeln.spinfo.classification.core.featureEngineering.featureWeighting.AbstractFeatureQuantifier;
import de.uni_koeln.spinfo.classification.zoneAnalysis.classifier.model.WekaModel;
import de.uni_koeln.spinfo.classification.zoneAnalysis.data.ZoneClassifyUnit;

/**
 * Text classification delegating the actual classification to a classifier
 * strategy.
 * @author jhermes
 */
public class WekaClassifier extends ZoneAbstractClassifier {

    private Classifier wekaClassifier;

    public WekaClassifier(Classifier c) {
        this.wekaClassifier = c;
    }

    public Classifier getClassifier() {
        return wekaClassifier;
    }

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    /* (non-Javadoc)
     * @see de.uni_koeln.spinfo.classification.core.classifier.AbstractClassifier#buildModel(java.util.List, de.uni_koeln.spinfo.classification.core.data.FeatureUnitConfiguration, de.uni_koeln.spinfo.classification.core.featureEngineering.featureWeighting.AbstractFeatureQuantifier, java.io.File)
     */
    @Override
    public Model buildModel(List<ClassifyUnit> cus, FeatureUnitConfiguration fuc, AbstractFeatureQuantifier fq,
            File trainingDataFile) {

        Instances trainingSet = initTrainingSet(cus);
        for (ClassifyUnit classifyUnit : cus) {
            trainingSet.add(instance(((ZoneClassifyUnit) classifyUnit), trainingSet));
        }

        //      // wir merken uns, dass das Training noch nicht abgeschlossen ist ...
        //      classifierBuilt = false;
        WekaModel model = new WekaModel();

        model.setTrainingData(trainingSet);
        model.setClassifierName(this.getClass().getSimpleName());
        model.setFQName(fq.getClass().getSimpleName());
        model.setDataFile(trainingDataFile);
        model.setFuc(fuc);
        model.setFUOrder(fq.getFeatureUnitOrder());

        return model;

    }

    @Override
    public boolean[] classify(ClassifyUnit cu, Model model) {
        try {
            Instances trainingData = ((WekaModel) model).getTrainingData();

            // beim ersten Aufruf prfen wir, ob der classifier bereits erstellt wurde:
            wekaClassifier.buildClassifier(trainingData);

            // Weka gibt als Ergebnis den Index des Klassen-Vektors zurck:
            int i = (int) wekaClassifier.classifyInstance(instance(cu, trainingData));
            boolean[] toReturn = new boolean[6];
            toReturn[i] = true;
            return toReturn;

        } catch (Exception e) {
            System.out.println(e.getClass());
            e.printStackTrace();
        }
        return null;
    }

    /*
     * Hier beschreiben wir die Struktur unserer Daten, damit Weka sie interpretieren kann, hierfr wird zunchst ein
     * Struktur-Vektor definiert, der in ein Instances-Objekt gepackt wird, das als Container fr die konkreten
     * Trainingsdaten dient.
     */
    private Instances initTrainingSet(List<ClassifyUnit> trainingData) {

        int vectorSize = trainingData.get(0).getFeatureVector().length;
        Set<Integer> classIDs = new TreeSet<Integer>();
        for (ClassifyUnit classifyUnit : trainingData) {
            ZoneClassifyUnit actual = (ZoneClassifyUnit) classifyUnit;
            classIDs.add(actual.getActualClassID());
        }
        /* Der Vektor enthlt die numerischen Merkmale (bei uns: tf-idf-Werte) sowie ein Klassenattribut: */
        ArrayList<Attribute> structureVector = new ArrayList<Attribute>(vectorSize + 1);
        /* Auch die Klasse wird in Weka als Vektor dargestellt: */
        ArrayList<String> classesVector = new ArrayList<String>();
        for (Integer c : classIDs) {
            /*
             * Da das Klassen-Attribut nicht numerisch ist (sondern, in Weka-Terminologie, ein nominales bzw.
             * String-Attribut), mssen hier alle mglichen Attributwerte angegeben werden:
             */
            classesVector.add(c + "");
        }
        /* An Stelle 0 unseres Strukturvektors kommt der Klassen-Vektor: */
        structureVector.add(new Attribute("topic", classesVector));
        for (int i = 0; i < vectorSize; i++) {
            /*
             * An jeder weiteren Position unseres Merkmalsvektors haben wir ein numerisches Merkmal (reprsentiert als
             * Attribute), dessen Name hier einfach seine Indexposition ist:
             */
            structureVector.add(new Attribute(i + "")); // Merkmal i, d.h. was? > TF-IDF
        }
        /*
         * Schliesslich erstellen wir einen Container, der Instanzen in der hier beschriebenen Struktur enthalten wird
         * (also unsere Trainingsbeispiele):
         */
        Instances result = new Instances("InstanceStructure", structureVector, vectorSize + 1);
        /*
         * Wobei wir hier erneut angeben muessen, an welcher Stelle der Merkmalsvektoren die Klasse zu finden ist:
         */
        result.setClassIndex(0);
        return result;
    }

    private Instance instance(ClassifyUnit cu, Instances trainingSet) {
        double[] values = cu.getFeatureVector();
        String classID = ((ZoneClassifyUnit) cu).getActualClassID() + "";
        Instance instance = new SparseInstance(1, values);
        /*
         * Weka muss 'erklrt' bekommen, was die Werte bedeuten - dies ist im Trainingsset beschrieben:
         */
        instance.setDataset(trainingSet);
        /*
         * Beim Training geben wir den Instanzen ein Klassenlabel, bei der Klassifikation ist die Klasse unbekannt:
         */
        if (classID == "0") {
            instance.setClassMissing(); // bei Klassifikation
        } else
            instance.setClassValue(classID); // beim Training
        return instance;
    }

}