/**
   * Returns an array with the bevavior of the classifier with test dataset
   *
   * @param classifier Classifier to obtain the error
   * @return double[] Behavior array
   */
  public double[] getTestClassificationBehaviorArray(IClassifier classifier) {

    // Dataset to be used
    DoubleTransposedDataSet dataset;
    if (dataNormalized) dataset = scaledTestData;
    else dataset = unscaledTestData;

    // Resulting array
    double[] result = new double[dataset.getNofobservations()];

    // Obtained outputs with this dataSet
    byte obtained[][] = classifier.classify(dataset.getAllInputs());

    // Expected outputs
    double expected[][] = dataset.getAllOutputs();

    // Init result
    for (int j = 0; j < dataset.getNofobservations(); j++) result[j] = 1;

    // Put a 0 in observations where the expected is not
    // the same than the observed
    for (int o = 0; o < obtained.length; o++) // For each output (o)
    for (int e = 0; e < obtained[o].length; e++) // For each example (e)
      if (obtained[o][e] != expected[o][e]) if (result[e] == 1) result[e] = 0;

    return result;
  }
  /**
   * Returns the train error value of a neural net with an specified error function
   *
   * @param nnind Neural net to obtain the error
   * @param errorFunction Error function to obtain the error
   * @return double Train error value
   */
  public double getTrainClassificationError(
      IClassifier classifier, IErrorFunction<byte[][]> errorFunction) {

    // Dataset to be used
    DoubleTransposedDataSet dataset;
    if (dataNormalized) dataset = scaledTrainData;
    else dataset = unscaledTrainData;

    // Obtained outputs with this dataSet
    byte obtained[][] = classifier.classify(dataset.getAllInputs());

    // Casting the outputs
    double doubleExpected[][] = dataset.getAllOutputs();
    byte expected[][] = new byte[doubleExpected.length][doubleExpected[0].length];
    for (int i = 0; i < doubleExpected.length; i++)
      for (int j = 0; j < doubleExpected[i].length; j++)
        expected[i][j] = (byte) doubleExpected[i][j];

    // Obtain error
    double error = errorFunction.calculateError(obtained, expected);

    // Return train error value
    return error;
  }
  /** Normalize data */
  private void normalizeData() {
    if (dataNormalized) {
      // Obtain maximum and minimum values
      unscaledMin = new double[unscaledTrainData.getNofvariables()];
      unscaledMax = new double[unscaledTrainData.getNofvariables()];
      double temp;
      for (int i = 0; i < unscaledTrainData.getNofvariables(); i++) {
        unscaledMax[i] = unscaledTrainData.getMaxValueOf(i);
        temp = unscaledTestData.getMaxValueOf(i);
        if (temp > unscaledMax[i]) unscaledMax[i] = temp;
        unscaledMin[i] = unscaledTrainData.getMinValueOf(i);
        temp = unscaledTestData.getMinValueOf(i);
        if (temp < unscaledMin[i]) unscaledMin[i] = temp;
      }

      // Obtain maximum and minimum desired values
      double[] scaledMin = new double[unscaledTrainData.getNofvariables()];
      double[] scaledMax = new double[unscaledTrainData.getNofvariables()];
      for (int i = 0; i < unscaledTrainData.getNofvariables(); i++) {
        if (i < unscaledTrainData.getNofinputs()) {
          scaledMin[i] = inputInterval.getLeft();
          scaledMax[i] = inputInterval.getRight();
        } else {
          scaledMin[i] = outputInterval.getLeft();
          scaledMax[i] = outputInterval.getRight();
        }
      }

      // Normalize trainData
      scaledTrainData = unscaledTrainData.copy();
      normalizer.scaleDS(scaledTrainData, scaledMax, scaledMin, unscaledMax, unscaledMin);

      // Normalize trainData
      scaledTestData = unscaledTestData.copy();
      normalizer.scaleDS(scaledTestData, scaledMax, scaledMin, unscaledMax, unscaledMin);
    }

    // Remove constant inputs
    int newNofinputs = 0;
    boolean[] toRemove = unscaledTrainData.obtainConstantsInputs();

    for (int i = 0; i < toRemove.length; i++) if (!toRemove[i]) newNofinputs++;

    unscaledTrainData.removeInputs(toRemove, newNofinputs);
    unscaledTestData.removeInputs(toRemove, newNofinputs);

    if (dataNormalized) {
      scaledTrainData.removeInputs(toRemove, newNofinputs);
      scaledTestData.removeInputs(toRemove, newNofinputs);

      // Log transformation
      if (logTransformation) {
        double[][] inputs = scaledTrainData.getAllInputs();

        for (int i = 0; i < inputs.length; i++)
          for (int j = 0; j < inputs[i].length; j++) inputs[i][j] = Math.log(inputs[i][j]);

        inputs = scaledTestData.getAllInputs();

        for (int i = 0; i < inputs.length; i++)
          for (int j = 0; j < inputs[i].length; j++) inputs[i][j] = Math.log(inputs[i][j]);
      }

    }

    // Log transformation
    else if (logTransformation) {
      double[][] inputs = unscaledTrainData.getAllInputs();

      for (int i = 0; i < inputs.length; i++)
        for (int j = 0; j < inputs[i].length; j++) inputs[i][j] = Math.log(inputs[i][j]);

      inputs = unscaledTestData.getAllInputs();

      for (int i = 0; i < inputs.length; i++)
        for (int j = 0; j < inputs[i].length; j++) inputs[i][j] = Math.log(inputs[i][j]);
    }
  }