package org.neuroph.eval;

import java.util.ArrayList;
import org.neuroph.core.NeuralNetwork;
import org.neuroph.core.data.DataSet;
import org.neuroph.util.data.sample.Sampling;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.commons.lang3.SerializationUtils;
import org.neuroph.core.learning.error.MeanSquaredError;
import org.neuroph.util.data.sample.SubSampling;

/**
 * This class implements multithreaded cross validation procedure. 
 * Splits data set into k subsets (folds), trains the network with data from k-1 and tests with one subset
 * Repeats the procedure k times each time using different subset for testing.
 *
 * @author Boris Fulurija
 * @author Lukic Sasa Multithreading
 * @author Zoran Sevarac
 */
public class CrossValidation {

    private static final Logger LOGGER = LoggerFactory.getLogger(CrossValidation.class.getName());

    /**
     * Neural network to train
     */
    private NeuralNetwork neuralNetwork;

    /**
     * Data set to use for training
     */
    private DataSet dataSet;

    /**
     * Data set sampling algorithm used. By default uses random subsampling
     * without repetition
     */
    private Sampling sampling;

    private int numberOfFolds;
    private int foldSize;

    /**
     * Evaluation procedure. Holds a collection of evaluators which can be
     * automatically added
     */
    private final Evaluation evaluation = new Evaluation();

    private CrossValidationResult results;

    private void initialize(NeuralNetwork neuralNetwork, DataSet dataSet, int numberOfFolds) {
        this.neuralNetwork = neuralNetwork;
        this.numberOfFolds = numberOfFolds;
        this.dataSet = dataSet;
        if (neuralNetwork.getOutputsCount() == 1) {
            this.evaluation.addEvaluator(new ClassifierEvaluator.Binary(0.5));
        } else {
            this.evaluation.addEvaluator(new ClassifierEvaluator.MultiClass(dataSet.getColumnNames()));
        }
        this.evaluation.addEvaluator(new ErrorEvaluator(new MeanSquaredError()));
    }

    /**
     * Creates a new instance of crrossvalidation for specified neural network, data set and number of folds.
     *
     * @param neuralNetwork
     * @param dataSet
     * @param foldCount number of folds to use
     */
    public CrossValidation(NeuralNetwork neuralNetwork, DataSet dataSet, int foldCount) { // number of folds/subsets
        initialize(neuralNetwork, dataSet, foldCount);
        this.sampling = new SubSampling(foldCount); // new RandomSamplingWithoutRepetition(numberOfSamples   
    }

    public Sampling getSampling() {
        return sampling;
    }

    public void setSampling(Sampling sampling) {
        this.sampling = sampling;
    }

    public Evaluation getEvaluation() {
        return evaluation;
    }

    public void run() throws InterruptedException, ExecutionException {

        results = new CrossValidationResult();
        this.results.numberOfFolds = this.numberOfFolds;
        this.results.numberOfInstances = this.dataSet.getRows().size();

        dataSet.shuffle();
        foldSize = dataSet.size() / numberOfFolds;

        ArrayList workersTasks = new ArrayList<>();
        for (int foldIdx = 0; foldIdx < numberOfFolds; foldIdx++) {
            workersTasks.add(new CrossValidationWorker(neuralNetwork, dataSet, foldIdx)); // invokeAll Futire
        }

        ExecutorService executor = Executors.newFixedThreadPool(4);
        List> evaluationResults = executor.invokeAll(workersTasks);
        executor.shutdown();

        for (Future evaluationResult : evaluationResults) {
            results.addEvaluationResult(evaluationResult.get());
        }

        results.calculateStatistics();
    }

    public void addEvaluator(Evaluator eval) {
        evaluation.addEvaluator(eval);
    }

    public  T getEvaluator(Class type) {
        return evaluation.getEvaluator(type);
    }

    public CrossValidationResult getResult() {
        return results;
    }

    private class CrossValidationWorker implements Callable {

        private final NeuralNetwork neuralNetwork;
        private final DataSet dataSet;
        private final int foldIndex;

        public CrossValidationResult getResults() {
            return results;
        }

        public Evaluation getEvaluation() {
            return evaluation;
        }

        public CrossValidationWorker(NeuralNetwork neuralNetwork, DataSet dataSet, int foldIndex) {
            this.neuralNetwork = neuralNetwork;
            this.dataSet = dataSet;
            this.foldIndex = foldIndex;
        }

        @Override
        public EvaluationResult call() {
            NeuralNetwork neuralNet = SerializationUtils.clone(this.neuralNetwork);

            DataSet trainingSet = new DataSet(dataSet.size() - foldSize);
            DataSet testSet = new DataSet(foldSize);

            int startIndex = foldSize * foldIndex;
            int endIndex = foldSize * (foldIndex + 1);

            for (int i = 0; i < dataSet.size(); i++) {
                if (i >= startIndex && i < endIndex) {
                    testSet.add(dataSet.getRowAt(i));
                } else {
                    trainingSet.add(dataSet.getRowAt(i));
                }
            }
            neuralNet.learn(trainingSet);
            EvaluationResult evaluationResult = new EvaluationResult();
            evaluationResult.setNeuralNetwork(neuralNet);
            evaluationResult = evaluation.evaluateDataSet(neuralNet, testSet);
            return evaluationResult;
        }

        /*private void testNetwork(NeuralNetwork neuralNetwork, DataSet testSet) {
        EvaluationResult evaluationResult = evaluation.evaluateDataSet(neuralNetwork, testSet); // this method should return all evaluation results
        
        results.addEvaluationResult(evaluationResult);
        //mean square error
        System.out.println("MeanSquare Error: " + evaluation.getEvaluator(ErrorEvaluator.class).getResult());
        ClassifierEvaluator evaluator;
        if (neuralNetwork.getOutputsCount() == 1) {
        evaluator = evaluation.getEvaluator(ClassifierEvaluator.Binary.class);
        } else {
        evaluator = evaluation.getEvaluator(ClassifierEvaluator.MultiClass.class);
        }
        
        //confusion matrix
        ConfusionMatrix confusionMatrix = evaluator.getResult();
        System.out.println("Confusion Matrix: \r\n" + confusionMatrix.toString());
        
        //classifivation metrics
        ClassificationMetrics[] metrics = ClassificationMetrics.createFromMatrix(confusionMatrix);     // add all of these to result
        
        for (ClassificationMetrics cm : metrics) {
        System.out.println(cm.toString());
        }
        }*/
    }
}

 

Ads help maintain this website.