csvmachine-learningwekaperceptron

Multilayer Neuronal Network Perceptron; FileWriter is not working, Output does not work properly


I tried to build up a machine learning model in Java with Weka. Here is my code:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;

import weka.classifiers.Evaluation;
import weka.classifiers.functions.MultilayerPerceptron;
import weka.classifiers.evaluation.Prediction;
import weka.core.Instances;
import weka.core.converters.ConverterUtils.DataSource;

public class multiLayerExample {
    public static void main(String[] args) throws Exception {

        String filename = "../train.arff";
        DataSource source = new DataSource(filename);
        Instances train = source.getDataSet();
        int cid1 = train.numAttributes() - 1;
        train.setClassIndex(cid1);
        
        Instances validation = DataSource.read(".../validation.arff");
        int cid2 = validation.numAttributes() - 1;
        validation.setClassIndex(cid2);

        Instances test = DataSource.read("../test1.arff");
        int cid3 = test.numAttributes() - 1;
        test.setClassIndex(cid3);

        MultilayerPerceptron tree = new MultilayerPerceptron();
        tree.buildClassifier(train);

        Evaluation eval = new Evaluation(train);
        eval.evaluateModel(tree, validation);
        System.out.println(eval.toSummaryString("\nResults_RF\n\n", false));
    //  System.out.println(eval.toClassDetailsString());
    //  System.out.println(eval.toMatrixString());

        ArrayList<Prediction> al = eval.predictions();
        ArrayList<String[]> as = new ArrayList<String[]>(al.size());
        for (int i = 0; i < al.size(); i++) {
            String[] s = new String[1];
            s[0] = al.get(i).toString();
            s[0] = s[0].substring(9, 11);
            as.add(s);
            System.out.println(s);
        }
        ArrayList<String[]> li = new ArrayList<String[]>(al.size());
        li.addAll(as);
         
        System.out.println(li.addAll(as));
//      String csv = "../output.csv";
//      CSVSaver writer = new CSVSaver(new FileWriter(csv));
//
//      writer.writeAll(li);
//      writer.close();
//      
        //Storing again in csv
        BufferedWriter writer1 = new BufferedWriter(
        new FileWriter("../output.csv"));
        System.out.print(li);
        writer1.write(li.toString());
        writer1.newLine();
        writer1.flush();
        writer1.close();
    }
}

The problems I have are: CSVSaver writer = new CSVSaver(new FileWriter(csv)); The following error message occurs: "CSVSaver cannot be resolved to a type" And if I comment it out and use the method inserted below it (//Storing again in csv), it inserts the following data in the output csv: "[[Ljava.lang.String;@53f65459, [Ljava.lang.String;@3b088d51, [Ljava.lang.String;@1786dec2,..."

What can I do, to make it work? Thanks for your help in advance!

I tried to write a new CSV Saver (see: //Storing again in csv) but the output is not readable. I expect the predictions to be written to the output file. The format is all numbers (double).


Solution

  • Weka's CSVSaver is for storing weka.core.Instances objects in CSV files, not just any lists.

    Also, Java arrays are objects but lack a custom toString() method. Instead, you will see things like [Ljava.lang.String;@3b088d51, which consists of the type signature and the object ID (see JNI type signatures).

    Based on your code, it looks like you are trying save the predicted values in a CSV file. But instead of turning predictions to strings and then extracting the relevant parts, you could just straight obtain the predicted value from the Prediction object (concrete implementation for numeric classes is NumericPrediction and NominalPrediction for nominal classes).

    I would rewrite your code for generating the CSV file with the predictions as follows:

    FileWriter fwriter1 = new FileWriter("../output.csv");
    BufferedWriter writer1 = new BufferedWriter(fwriter1);
    for (Prediction p: eval.predictions()) {
      writer1.write("" + p.predicted());
      writer1.newLine();
    }
    writer1.flush();
    writer1.close();
    fwriter1.close();
    

    If your class should be nominal, .predicted() will return the label index. This index you can cast to int and retrieve the label from your class attribute:

    String label = train.classAttribute().value((int) p.predicted());
    

    NB: You should always make sure that your train, validation and test set are compatible to avoid strange behavior from your classifier, using the equalHeadersMsg method:

    String msg;
    msg = train.equalHeadersMsg(test);
    if (msg != null)
      throw new IllegalStateException("Train/test not compatible:\n" + msg);
    msg = train.equalHeadersMsg(validation);
    if (msg != null)
      throw new IllegalStateException("Train/validation not compatible:\n" + msg);