/*
* Encog(tm) Core v3.4 - Java Version
* http://www.heatonresearch.com/encog/
* https://github.com/encog/encog-java-core
* Copyright 2008-2016 Heaton Research, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* For more information on Heaton Research copyrights, licenses
* and trademarks visit:
* http://www.heatonresearch.com/copyright
*/
package org.encog.mathutil.error;
import org.encog.ml.MLRegression;
import org.encog.ml.data.MLData;
import org.encog.ml.data.MLDataPair;
import org.encog.ml.data.MLDataSet;
import org.encog.ml.ea.exception.EARuntimeError;
/**
* A normalized error will generally be in the approximate range between 0 and 1. This allows normalized errors to be
* compared across multiple datasets. This class implements two types of normalized error calculation: Normalized
* root-mean-square deviation (NRMSD) and coefficient of variation of the RMSD, CV(RMSD).
*
* https://en.wikipedia.org/wiki/Root-mean-square_deviation
*/
public class NormalizedError {
/**
* The max target value in the dataset.
*/
private double min;
/**
* The min target value in the dataset.
*/
private double max;
/**
* The mean target value in the dataset.
*/
private double mean;
/**
* The standard deviation (SD) of the target value.
*/
private double sd;
/**
* The number of target values considered.
*/
private int outputCount;
/**
* Construct the normalized error calculator.
* @param theData The dataset to use.
*/
public NormalizedError(MLDataSet theData) {
this.min = Double.POSITIVE_INFINITY;
this.max = Double.NEGATIVE_INFINITY;
this.outputCount = 0;
double sum = 0;
for(MLDataPair pair: theData) {
for(double d: pair.getIdealArray()) {
this.min = Math.min(d,this.min);
this.max = Math.max(d,this.max);
sum += d;
outputCount++;
}
}
this.mean = sum / outputCount;
sum = 0;
for(MLDataPair pair: theData) {
for(double d: pair.getIdealArray()) {
double z = d - this.mean;
sum += z * z;
}
}
this.sd = Math.sqrt(sum/this.outputCount);
}
/**
* Calculate the sum of squares of target of the target variable.
* @param theData The dataset to use.
* @param theModel The model to evaluate.
* @return The sum of squares.
*/
private double calculateSum(MLDataSet theData,MLRegression theModel) {
double sum = 0;
for(MLDataPair pair: theData) {
MLData actual;
try {
actual = theModel.compute(pair.getInput());
} catch (EARuntimeError e) {
return Double.NaN;
}
for(int i=0;i<pair.getIdeal().size();i++) {
double d = actual.getData(i) - pair.getIdeal().getData(i);
d = d * d;
sum+=d;
}
}
return sum;
}
/**
* Calculate the error as the coefficient of variation of the RMSD (CV(RMSD)).
* @param theData The dataset to evaluate with.
* @param theModel The model to evaluate.
* @return The CV(RMSD) error.
*/
public double calculateNormalizedMean(MLDataSet theData,MLRegression theModel) {
double sum = calculateSum(theData,theModel);
if( Double.isNaN(sum) || Double.isInfinite(sum) ) {
return Double.NaN;
}
return Math.sqrt (sum/this.outputCount) / Math.abs(this.mean);
}
/**
* Calculate the error as the Normalized root-mean-square deviation (NRMSD)
* @param theData The dataset to evaluate with.
* @param theModel The model to evaluate.
* @return The NRMSD error.
*/
public double calculateNormalizedRange(MLDataSet theData,MLRegression theModel) {
double sum = calculateSum(theData,theModel);
if( Double.isNaN(sum) || Double.isInfinite(sum) ) {
return Double.NaN;
}
return Math.sqrt (sum/this.outputCount) / (this.max - this.min);
}
}