8

I trained and created a J48 model using WEKA gui. I saved the model file to my computer and now I would like to use it to classify a single instance in my Java code. I would like to get a prediction for the attribute "cluster". What I do is the following:

public void classify(double lat, double lon, double co)
{            

// Create attributes to be used with classifiers
                    Attribute latitude = new Attribute("latitude");
                    Attribute longitude = new Attribute("longitude");
                    Attribute carbonmonoxide = new Attribute("co");

                    // Create instances for each pollutant with attribute values latitude, longitude and pollutant itself
                    inst_co = new DenseInstance(4);

                    // Set instance's values for the attributes "latitude", "longitude", and "pollutant concentration"
                    inst_co.setValue(latitude, lat);
                    inst_co.setValue(longitude, lon);
                    inst_co.setValue(carbonmonoxide, co);
                    inst_co.setMissing(cluster);


    Classifier cls_co = (Classifier) weka.core.SerializationHelper.read("/CO_J48Model.model");//load classifier from file

                    // Test the model
        double result = cls_co.classifyInstance(inst_co);
}

However, I get an IndexArrayOutofBoundsException on the line inst_co.setValue(latitude, lat);. I couldn't find the reason for this exception. I will appreciate if someone could point me in the right direction.

Has QUIT--Anony-Mousse
  • 76,138
  • 12
  • 138
  • 194
Erol
  • 6,478
  • 5
  • 41
  • 55

2 Answers2

8

You need to add your inst_co to your data set, an Instances object. Following code should work.

import java.util.ArrayList;

import weka.classifiers.Classifier;
import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.Instance;
import weka.core.Instances;

public class QuestionInstanceClassifiy {

    public static void main(String[] args) {
        QuestionInstanceClassifiy q = new QuestionInstanceClassifiy();
        double result = q.classify(1.0d, 1, 1);
        System.out.println(result);
    }

    private Instance inst_co;

    public double classify(double lat, double lon, double co)  {

        // Create attributes to be used with classifiers
        // Test the model
        double result = -1;
        try {

            ArrayList<Attribute> attributeList = new ArrayList<Attribute>(2);

            Attribute latitude = new Attribute("latitude");
            Attribute longitude = new Attribute("longitude");
            Attribute carbonmonoxide = new Attribute("co");

            ArrayList<String> classVal = new ArrayList<String>();
            classVal.add("ClassA");
            classVal.add("ClassB");


            attributeList.add(latitude);
            attributeList.add(longitude);
            attributeList.add(carbonmonoxide);
            attributeList.add(new Attribute("@@class@@",classVal));

            Instances data = new Instances("TestInstances",attributeList,0);


            // Create instances for each pollutant with attribute values latitude,
            // longitude and pollutant itself
            inst_co = new DenseInstance(data.numAttributes());
            data.add(inst_co);

            // Set instance's values for the attributes "latitude", "longitude", and
            // "pollutant concentration"
            inst_co.setValue(latitude, lat);
            inst_co.setValue(longitude, lon);
            inst_co.setValue(carbonmonoxide, co);
            // inst_co.setMissing(cluster);

            // load classifier from file
            Classifier cls_co = (Classifier) weka.core.SerializationHelper
                    .read("/CO_J48Model.model");

            result = cls_co.classifyInstance(inst_co);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;
    }
}

You create data object from Instances. Add your instance to this data. After that you can set your values in Instance.

Instances data = new Instances("TestInstances",attributeList,0);
inst_co = new DenseInstance(data.numAttributes());
data.add(inst_co);

I suggest getting header information and Instances values from external file or creating this information only once.

Atilla Ozgur
  • 14,339
  • 3
  • 49
  • 69
  • Thank you for the great answer. Just to clarify, classA and classB are the possible outcomes of classification, i.e. my cluster names, right? I guess they need to be the same with the ones used while I was creating the model. – Erol Oct 23 '12 at 14:52
  • Not working, I am getting weka.core.UnassignedDatasetException: DenseInstance doesn't have access to a dataset! error. Guess I will have to assign it to a dataset, maybe the one I used to train it? – Erol Oct 23 '12 at 15:40
  • @babatenor you need to assign it to data set with same header. Their header information should be same – Atilla Ozgur Oct 24 '12 at 09:05
  • Just to make sure: I read in my arff file with the data that I used with the classifier, assign my instance to this data set and also assign a class value? – Erol Oct 24 '12 at 09:25
  • @babatenor could you give a simple example of your arff file?. Header and 3-4 lines of data? – Atilla Ozgur Oct 24 '12 at 10:00
  • @babatenor You read in your arff file with the data that you used with the classifier, assign your instance to this data set, but DO NOT NEED TO assign a class value? your classifier result will be this value. – Atilla Ozgur Oct 24 '12 at 10:01
  • I was using different attributes than the ones I used with my classifier. That was the problem. I made a little edit to your code that assigns a class value to the Instances variable so that the classifier knows which attribute it will be guessing. It's the final working version. Thank you very much Atilla. Your help is appreciated. – Erol Oct 24 '12 at 11:50
3

Actually I tried in my situation is call the instance.setDataSet() method,not the addInstance method.So you code should be inst_co.setDataSet(data).

changer
  • 51
  • 2