package performance;

import data.DataSet;
import data.core.Norm;
import gnu.trove.list.TIntList;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.set.hash.TIntHashSet;
import model.Predictable;
import model.Trainable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Random;
import java.util.function.IntPredicate;
import java.util.stream.IntStream;

/**
 * Created by hanxuan on 9/20/15 for machine_learning.
 */
public class CrossValidationEvaluator {

    private static final Logger log = LogManager.getLogger(CrossValidationEvaluator.class);

    private DataSet rowDataSet = null;

    private int[][] kFoldIndex = null;

    private Evaluator evaluator;

    private Norm norm;

    public CrossValidationEvaluator(Evaluator eva, DataSet dataSet, int k, Norm norm) {

        evaluator = eva;
        rowDataSet = dataSet;
        this.norm = norm;

        TIntList instancesIndex = new TIntArrayList(IntStream.range(0, rowDataSet.getInstanceLength()).toArray());
        instancesIndex.shuffle(new Random());
        kFoldIndex = new int[k][];
        int pointer = 0;
        for (int i = 0; i < k; i++) {
            int len = Math.min(rowDataSet.getInstanceLength() / k, instancesIndex.size() - pointer);
            int[] a = new int[len];
            for (int j = 0; j < len; j++) {
                a[j] = instancesIndex.get(pointer++);
            }
            kFoldIndex[i] = a;
        }
    }

    public void crossValidateEvaluate(Trainable model) {

        double avgOnTest = 0;
        double avgOnTrain = 0;

        for (int i = 0; i < kFoldIndex.length; i++) {

            TIntHashSet testIndexes = new TIntHashSet(kFoldIndex[i]);
            IntPredicate pred = (n) -> !testIndexes.contains(n);
            int[] trainIndexes = IntStream.range(0, rowDataSet.getInstanceLength()).filter(pred).toArray();

            DataSet trainSet = rowDataSet.subDataSetByRow(trainIndexes);
            DataSet testSet = rowDataSet.subDataSetByRow(testIndexes.toArray());

            if (norm == null){}
            else if (norm.equals(Norm.MEANSD)) {
                trainSet.meanVarianceNorm();
                testSet.meanVarianceNorm(trainSet.getMeanOrMin(), trainSet.getSdOrMax());
            } else if (norm.equals(Norm.MINMAX)) {
                trainSet.shiftCompressNorm();
                testSet.shiftCompressNorm(trainSet.getMeanOrMin(), trainSet.getSdOrMax());
            }

            model.initialize(trainSet);
            model.train();
            Predictable trainedModel = model.offer();

            evaluator.setTestSet(testSet);
            evaluator.getPredictLabel(trainedModel);
            double performOnTest = evaluator.evaluate();

            evaluator.setTestSet(trainSet);
            evaluator.getPredictLabel(trainedModel);
            double performOnTrain = evaluator.evaluate();


            log.info("FOLD {}/test{}/train{}", i, performOnTest, performOnTrain);

            avgOnTest += performOnTest;
            avgOnTrain += performOnTrain;
        }

        avgOnTest /= kFoldIndex.length;
        avgOnTrain /= kFoldIndex.length;
        log.info("avgOnTest {}, avgOnTrain {}", avgOnTest, avgOnTrain);
    }
}

@@ -1886,24 +1886,267 @@
 toArray();%0A%0A
+%0A%0A            if (norm == null)%7B%7D%0A            else if (norm.equals(Norm.MEANSD)) %7B%0A                rowDataSet.meanVarianceNorm();%0A            %7Delse if (norm.equals(Norm.MINMAX)) %7B%0A                rowDataSet.shiftCompressNorm();%0A            %7D%0A%0A
             
@@ -2284,24 +2284,26 @@
 oArray());%0A%0A
+//
             
@@ -2314,32 +2314,34 @@
 norm == null)%7B%7D%0A
+//
             else
@@ -2365,32 +2365,34 @@
 Norm.MEANSD)) %7B%0A
+//
                 
@@ -2412,32 +2412,34 @@
 VarianceNorm();%0A
+//
                 
@@ -2504,32 +2504,34 @@
 .getSdOrMax());%0A
+//
             %7D el
@@ -2557,32 +2557,34 @@
 Norm.MINMAX)) %7B%0A
+//
                 
@@ -2605,32 +2605,34 @@
 CompressNorm();%0A
+//
                 
@@ -2702,24 +2702,26 @@
 SdOrMax());%0A
+//
             

normalize all data set including training and testing