Cannot handle multi-valued nominal class - JAVA

4.8k views Asked by At

I'm trying to pass a .arff file to LinearRegression object and while doing so it gives me this exception Cannot handle multi-valued nominal class!.

What actually happening is i'm performing Attribute selection using CFSSubsetEval evaluater and search as GreedyStepwise after doing so, passing those attributes to LinearRegression as follows

LinearRegression rl=new LinearRegression(); rl.buildClassifier(data);    

data is the Instance object which has the data from .arff file which previously converted to nominal values using weka only. Am i doing anything wrong here? I was trying to search for this error on google but couldn't find one.

Code

package com.attribute;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Random;

import weka.attributeSelection.AttributeSelection;
import weka.attributeSelection.CfsSubsetEval;
import weka.attributeSelection.GreedyStepwise;
import weka.classifiers.Evaluation;
import weka.classifiers.functions.LinearRegression;
import weka.classifiers.meta.AttributeSelectedClassifier;
import weka.classifiers.trees.J48;
import weka.core.Instances;
import weka.core.Utils;
import weka.filters.supervised.attribute.NominalToBinary;

/**
 * performs attribute selection using CfsSubsetEval and GreedyStepwise
 * (backwards) and trains J48 with that. Needs 3.5.5 or higher to compile.
 * 
 * @author FracPete (fracpete at waikato dot ac dot nz)
 */
public class AttributeSelectionTest2 {

    /**
     * uses the meta-classifier
     */
    protected static void useClassifier(Instances data) throws Exception {
        System.out.println("\n1. Meta-classfier");
        AttributeSelectedClassifier classifier = new AttributeSelectedClassifier();
        CfsSubsetEval eval = new CfsSubsetEval();
        GreedyStepwise search = new GreedyStepwise();
        search.setSearchBackwards(true);
        J48 base = new J48();
        classifier.setClassifier(base);
        classifier.setEvaluator(eval);
        classifier.setSearch(search);
        Evaluation evaluation = new Evaluation(data);
        evaluation.crossValidateModel(classifier, data, 10, new Random(1));
        System.out.println(evaluation.toSummaryString());
    }

    /**
     * uses the low level approach
     */
    protected static void useLowLevel(Instances data) throws Exception {
        System.out.println("\n3. Low-level");
        AttributeSelection attsel = new AttributeSelection();
        CfsSubsetEval eval = new CfsSubsetEval();
        GreedyStepwise search = new GreedyStepwise();
        search.setSearchBackwards(true);
        attsel.setEvaluator(eval);
        attsel.setSearch(search);
        attsel.SelectAttributes(data);
        int[] indices = attsel.selectedAttributes();
        System.out.println("selected attribute indices (starting with 0):\n"
                + Utils.arrayToString(indices));
        useLinearRegression(indices, data);
    }

    protected static void useLinearRegression(int[] indices, Instances data) throws Exception{
        System.out.println("\n 4. Linear-Regression on above selected attributes");

        BufferedReader reader = new BufferedReader(new FileReader(
                "C:/Entertainement/MS/Fall 2014/spdb/project 4/healthcare.arff"));
        Instances data1 = new Instances(reader);
        data.setClassIndex(data.numAttributes() - 1);
        /*NominalToBinary nb = new NominalToBinary();
        for(int i=0;i<=20; i++){
         //Still coding left here, create an Instance variable to store the data from 'data' variable for given indices
            Instances data_lr=data1.
        }*/
        LinearRegression rl=new LinearRegression(); //Creating a LinearRegression Object to pass data1
        rl.buildClassifier(data1);
    }
    /**
     * takes a dataset as first argument
     * 
     * @param args
     *            the commandline arguments
     * @throws Exception
     *             if something goes wrong
     */
    public static void main(String[] args) throws Exception {
        // load data
        System.out.println("\n0. Loading data");
        BufferedReader reader = new BufferedReader(new FileReader(
                "C:/Entertainement/MS/Fall 2014/spdb/project 4/healthcare.arff"));
        Instances data = new Instances(reader);

        if (data.classIndex() == -1)
            data.setClassIndex(data.numAttributes() - 14);

        // 1. meta-classifier
        useClassifier(data);

        // 2. filter
        //useFilter(data);

        // 3. low-level
        useLowLevel(data);
    }
}

NOTE : As i have not written code to build an instance variable with 'indices' attributes, i'm (for the sake of program to run) loading data from the same original file.

I don't know how to upload a file for sample data, but it looks something like this. [link] (https://scontent-a-dfw.xx.fbcdn.net/hphotos-xfa1/t31.0-8/p552x414/10496920_756438941076936_8448023649960186530_o.jpg)

2

There are 2 answers

3
Matthew Spencer On BEST ANSWER

Based on your data, it appears that your last attribute is a nominal data type (Contains mostly numbers, but there are some strings as well). LinearRegression will not allow the prediction of nominal classes.

What you could potentially do to ensure that your given dataset works is run it through the Weka Explorer with Linear Regression and see if the desired outcome is generated. Following this, there is a good chance that the data will work correctly in your code.

Hope this Helps!

0
Дима Менько On

Here is example of dataset for LinearRegression (source)

@RELATION house
@ATTRIBUTE houseSize NUMERIC
@ATTRIBUTE lotSize NUMERIC
@ATTRIBUTE bedrooms NUMERIC
@ATTRIBUTE granite NUMERIC
@ATTRIBUTE bathroom NUMERIC
@ATTRIBUTE sellingPrice NUMERIC

@DATA
3529,9191,6,0,0,205000
3247,10061,5,1,1,224900
4032,10150,5,0,1,197900
2397,14156,4,1,0,189900
2200,9600,4,0,1,195000
3536,19994,6,1,1,325000
2983,9365,5,0,1,230000