DoubleMath.java [src/java/m/cfa] Revision: Date:
package m.cfa;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import org.apache.commons.math.ArgumentOutsideDomainException;
import org.apache.commons.math.analysis.interpolation.SplineInterpolator;
import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
/**
* Last Updated: 20-April-2017
* @author Tyler Wible
* @since 21-June-2012
*/
class sort1_smallToLargeDoubleMath implements Comparator<double[]>{
//Compares the first entry and sorts smallest to largest
public int compare(final double[] entry1, final double[] entry2) {
double value1 = entry1[0];
double value2 = entry2[0];
//Compare and return the second entries
return Double.compare(value1,value2);
}
}
public class DoubleMath{
private static double[] convertArray(ArrayList<Double> array){
double[] newArray = new double[array.size()];
for(int i=0; i<array.size(); i++){
newArray[i] = array.get(i);
}
return newArray;
}
/**
* Finds the maximum value of a double[] array
* @param array the double[] array
* @return the maximum of the above array as a double
*/
public static double max(double[] array){
double maximum = -9999;
for(int i=0; i<array.length; i++){
if(i == 0){
maximum = array[i];
}else{
if(Double.compare(maximum, array[i]) < 0){
maximum = array[i];
}
}
}
return maximum;
}
/**
* Finds the maximum value of a ArrayList<Double>
* @param array the ArrayList<Double> array
* @return the maximum of the above array as a double
*/
public static double max(ArrayList<Double> array){
double[] newArray = convertArray(array);
double maximum = max(newArray);
return maximum;
}
/**
* Finds the minimum value of a double[] array
* @param array the double[] array
* @return the minimum of the above array as a double
*/
public static double min(double[] array){
double minimum = -9999;
for(int i=0; i<array.length; i++){
if(i == 0){
minimum = array[i];
}else{
if(Double.compare(minimum, array[i]) > 0){
minimum = array[i];
}
}
}
return minimum;
}
/**
* Finds the minimum value of a ArrayList<Double>
* @param array the ArrayList<Double> array
* @return the minimum of the above array as a double
*/
public static double min(ArrayList<Double> array){
double[] newArray = convertArray(array);
double minimum = min(newArray);
return minimum;
}
/**
* Calculates the sum of a double[] array
* @param array the array to be summed
* @return the sum of the array
*/
public static double sum(double[] array){
double sum = 0;
//Calculate the sum of the array
for(int i=0; i<array.length; i++){
sum = sum + array[i];
}
return sum;
}
/**
* Calculates the sum of a ArrayList<Double>
* @param array the array to be summed
* @return the sum of the array
*/
public static double sum(ArrayList<Double> array){
double[] newArray = convertArray(array);
double sum = sum(newArray);
return sum;
}
/**
* Rounds the double to the number of decimal places "n" where roundingValue = 10^n
* For example if the roundingValue is equal to 10, then the returned value would have 1 decimal place
* @param originalValue the original double value to be rounded
* @param decimalPlaces is equal to the number of decimal places desired
* @return a double rounded value of the orignal data
*/
public static double round(double originalValue, double decimalPlaces){
double decimals = Math.pow(10, decimalPlaces);
double roundedValue = Math.round(originalValue*decimals);
roundedValue = roundedValue/decimals;
return roundedValue;
}
/**
* Rounds the double[] array to the number of decimal places "n" where roundingValue = 10^n
* For example if the roundingValue is equal to 10, then the returned matrix would contain the original matrix with 1 decimal place
* @param array the original double[] matrix to be rounded
* @param decimalPlaces is equal to the number of decimal places desired
* @return a double[] array of the rounded values of the original data
*/
public static double[] roundColumn(double[] array, double decimalPlaces){
double[] roundedArray = new double[array.length];
for(int i=0; i<array.length; i++){
roundedArray[i] = round(array[i], decimalPlaces);
}
return roundedArray;
}
/**
* Calculates the arithmetic mean of the provided double[] array
* @param array the double[] array of which the arithmetic mean is desired
* @return the double value of the arithmetic mean of the data array
*/
public static double meanArithmetic(double[] array){
//Calculates the average of a double array
double sum = sum(array);
double count = array.length;
if(count == 0){//fix divide by zero errors
count = 1;
}
double average = sum/count;
return average;
}
/**
* Calculates the arithmetic mean of the provided ArrayList<Double>
* @param array the ArrayList<Double> of which the arithmetic mean is desired
* @return the double value of the arithmetic mean of the data array
*/
public static double meanArithmetic(ArrayList<Double> array){
double[] newArray = convertArray(array);
double average = meanArithmetic(newArray);
return average;
}
/**
* Calculates the harmonic mean of the provided double[] array,
* only calculates for real positive values.
*
* Note that the final estimate of the harmonic mean is a weighted average
* of the harmonic mean of the non-zero elements and zero.
* @param array the double[] array of which the harmonic mean is desired
* @return the double value of the harmonic mean of the data array
*/
public static double meanHarmonic(double[] array){
//Calculate properties of harmonic mean
double reciprocalSum = 0, nZeros = 0, nData = 0;
for(int i=0; i<array.length; i++){
if(array[i] > 0){
reciprocalSum = reciprocalSum + (1/array[i]);//sum of reciprocals
}else{
nZeros++;
}
nData++;
}
//Compute harmonic mean (with correction for the number of zero items in the array)
double meanHarmonic = (nData - nZeros) / (reciprocalSum * ((nData - nZeros)/nData));
return meanHarmonic;
}
/**
* Calculates the harmonic mean of the provided ArrayList<Double> array,
* only calculates for real positive values.
*
* Note that the final estimate of the harmonic mean is a weighted average
* of the harmonic mean of the non-zero elements and zero.
* @param array the ArrayList<Double> array of which the harmonic mean is desired
* @return the double value of the harmonic mean of the data array
*/
public static double meanHarmonic(ArrayList<Double> array){
double[] newArray = convertArray(array);
double meanHarmonic = meanHarmonic(newArray);
return meanHarmonic;
}
/**
* Finds the average of the Log10 of a double[] array
* @param array the double[] array that the average is desired for
* @return the double value of the average of the Log10 of the data array
*/
public static double Average_Log10(double[] array){
//Matlab code: Xmean = mean(log10(data));
double[] log10array = Log10(array);
double averageLog10 = meanArithmetic(log10array);
return averageLog10;
}
/**
* Calculates and returns the Java Math.Log10 value of each element in the double[] data array
* @param array the double[] array containing the pre-Log10 values
* @return the resulting double[] array containing the Log10 values of the "data" array
*/
public static double[] Log10(double[] array){
//Matlab code: X = log10(data);
//Returns an array containing the Log10 value of each element in the data array
double[] log10Array = new double[array.length];
for(int i=0; i<array.length; i++){//Loop through rows
log10Array[i] = Math.log10(array[i]);
}
return log10Array;
}
/**
* Calculates and returns the Java Math.Log10 value of the specified column in the double[all][column] data array
* @param array the double[][] array containing the pre-Log10 values
* @param column the column of data to be calculated with
* @return the resulting double[] array containing the Log10 values of the "data" array
*/
public static double[] Log10(double[][] array, int column){
//Matlab code: X = log10(data);
//Returns an array containing the Log10 value of each element in the data array
double[] log10Array = new double[array.length];
for(int i=0; i<array.length; i++){//Loop through rows
log10Array[i] = Math.log10(array[i][column]);
}
return log10Array;
}
/**
* Performs a spline interpolation and computes an array of y values using the Xarray and Yarray evaluated at the xarray points
* @param Xarray an array of existing X points
* @param Yarray an array of existing Y points corresponding to the above Xarray
* @param xarray an array of x points for which y points are desired
* @return an array of y points corresponding to the x points of the xarray after a spline interpolation between Xarray and Yarray
* @throws ArgumentOutsideDomainException
*/
public static double[] splineInterpolation(double[] Xarray, double[] Yarray, double[] xarray) throws ArgumentOutsideDomainException{
//Interpolate each y point for each provided x point using the above interpolatoer
double[] yarray = new double[xarray.length];
for(int i=0; i<xarray.length; i++){
yarray[i] = splineInterpolation(Xarray, Yarray, xarray[i]);
}
return yarray;
}
/**
* Performs a spline interpolation and computes a y value using the Xarray and Yarray evaluated at the xValue point
* @param Xarray a double[] array of existing X points
* @param Yarray a double[] array of existing Y points corresponding to the above Xarray
* @param xValue a double x point for which y point is desired
* @return a double y point corresponding to the x point of the xValue after a spline interpolation between Xarray and Yarray
*/
public static double splineInterpolation(double[] Xarray, double[] Yarray, double xValue) throws ArgumentOutsideDomainException{
//Set up the spline interplator
SplineInterpolator splineInterp2 = new SplineInterpolator();
PolynomialSplineFunction splineFunction2 = splineInterp2.interpolate(Xarray, Yarray);
//Interpolate each y point for each provided x point using the above interpolatoer
double yValue = splineFunction2.value(xValue);
return yValue;
}
/**
* Performs a linear interpolation and computes an array of y values using the Xarray and Yarray evaluated at the xArray points
* @param Xarray a double[] array of existing X points
* @param Yarray a double[] array of existing Y points corresponding to the above Xarray
* @param xArray a double[] array x points for which y points is desired
* @return a double[] array of y points corresponding to the array of x points of the xArray after a linear interpolation between Xarray and Yarray
*/
public static double[] linearInterpolation(double[] Xarray, double[] Yarray, double[] xArray){
//Interpolate a y value for each x value in xArray
double[] yArray = new double[xArray.length];
for(int i=0; i<xArray.length; i++){
yArray[i] = linearInterpolation(Xarray, Yarray, xArray[i]);
}
return yArray;
}
/**
* Performs a linear interpolation and computes a y value using the Xarray and Yarray evaluated at the xValue point
* @param Xarray a double[] array of existing X points
* @param Yarray a double[] array of existing Y points corresponding to the above Xarray
* @param xValue a double x point for which y point is desired
* @return a double y point corresponding to the x point of the xValue after a linear interpolation between Xarray and Yarray
*/
public static double linearInterpolation(double[] Xarray, double[] Yarray, double xValue){
double yValue = 0;
//Sort the Xarray based on values as to properly interpolate between points
double[][] tempMatrix = new double[Xarray.length][3];
for(int i=0; i<Xarray.length; i++){
tempMatrix[i][0] = Xarray[i];
tempMatrix[i][1] = Yarray[i];
tempMatrix[i][2] = i;
}
Arrays.sort(tempMatrix, new sort1_smallToLargeDoubleMath());
Xarray = DoubleArray.getColumn(tempMatrix, 0);
Yarray = DoubleArray.getColumn(tempMatrix, 1);
//Interpolate bewtween the arrays
for(int i=0; i<Xarray.length; i++){
if(i == 0 && xValue < Xarray[0]){
//If xValue is smaller than the first Xarray value, extrapolate based on the slope bewteen the first two points in Xarray and Yarray
yValue = ((Yarray[i+1] - Yarray[i])/(Xarray[i+1] - Xarray[i]))*(xValue - Xarray[i]) + Yarray[i];
System.err.println("The x value: " + xValue + " is smaller than the smallest provided X value: " + Xarray[0] + ". Therefore it's corresponding y value: " + yValue + " was extrapolated from the dataset.");
break;
}else if(xValue == Xarray[i]){
yValue = Yarray[i];
break;
}else if(i != 0 && Xarray[i-1] < xValue && xValue < Xarray[i]){
yValue = ((xValue - Xarray[i-1])/(Xarray[i] - Xarray[i-1]))*(Yarray[i] - Yarray[i-1]) + Yarray[i-1];
break;
}else if(i == (Xarray.length-1) && xValue > Xarray[i]){
//If xValue is larger than the last Xarray value, extrapolate based on the slope bewteen the last two points in Xarry and Yarray
yValue = ((Yarray[i-1] - Yarray[i])/(Xarray[i-1] - Xarray[i]))*(xValue - Xarray[i]) + Yarray[i];
System.err.println("The x value: " + xValue + " is larger than the largest provided X value: " + Xarray[i] + ". Therefore it's corresponding y value: " + yValue + " was extrapolated from the dataset.");
break;
}
}
return yValue;
}
/**
* Sub-function to calculate a percentile of a dataset
* @param array input list data for percentile (double[])
* @param percentile_type which percentile value is desired 0.25, or 0.95, etc.
* @return percentile of the dataset.
*/
public static double Percentile_function (double[] array, double percentile_type){
//Sort Data
Arrays.sort(array);
double percentile = -9999;
//return quartiles for small datasets early, if not small, then continue to find which percentile is asked for
if(array.length == 0){
percentile = -9999;
}else if(array.length == 1){
percentile = array[0];
}else if(Double.compare(percentile_type, 0.5) == 0){
//Find median of dataset
percentile = median(array);
}else{
//Find rank of the desired percentile
double rank = percentile_type*(array.length + 1);//ex: 0.95*(n + 1) = rank of 95th percentile
try{
int rank_int = Integer.parseInt(String.valueOf(rank));
//If the rank is an integer find the value corresponding to it
for(int i=0; i<array.length; i++){
if(i+1 == rank_int){//i+1 is to compensate for Java's zero-based indexing system
percentile = array[i];
break;
}
}
}catch(NumberFormatException e){
//If the rank is not an integer average it between the two nearest ranks
for(int i=0; i<array.length; i++){
if(i+1 < rank && i+2 >= rank){//i+1 is to compensate for Java's zero-based indexing system
try{
percentile = (array[i] + array[i+1])/2;
}catch(IndexOutOfBoundsException err){
percentile = array[i];
System.err.println("Insufficient data to calculate the desired percentile accurately");
}
break;
}else if(i+1 == array.length){
percentile = array[i];
System.err.println("Insufficient data to calculate the desired percentile accurately");
}
}
}
}
return percentile;
}
/**
* Sub-function to calculate a percentile of a dataset
* @param array input list data for percentile (List<Double>)
* @param percentile_type which percentile value is desired 0.25, or 0.95, etc.
* @return percentile of the dataset.
*/
public static double Percentile_function (ArrayList<Double> array, double percentile_type){
double[] newArray = convertArray(array);
double percentile = Percentile_function(newArray, percentile_type);
return percentile;
}
/**
* Sub-function to calculate the median of a dataset
* @param array input list data for median
* @return median of the dataset.
*/
public static double median(double[] array){
//sort dataset before calculating median
Arrays.sort(array);
//Find the median
int midpoint = (array.length)/2;
double median = -9999;
if(array.length == 0){
median = -9999;
}else if(array.length%2 == 1){
median = array[midpoint];
}else{
median = (array[midpoint-1] + array[midpoint])/2;
}
return median;
}
/**
* Sub-function to calculate the median of a dataset
* @param array input list data for median
* @return median of the dataset.
*/
public static double median(ArrayList<Double> array){
double[] newArray = convertArray(array);
double median = median(newArray);
return median;
}
/**
* Sub-function to calculate the standard deviation of the population
* @param array input list data for standard deviation
* @return the population standard deviation of the dataList.
*/
public static double StandardDeviationSample(double[] array){
double variance = VarianceSample(array);
double standardDeviation = Math.pow(variance,0.5);
return standardDeviation;
}
/**
* Sub-function to calculate the standard deviation of a dataset
* @param array input list data for standard deviation
* @return standard deviation of the dataset.
*/
public static double StandardDeviationSample(ArrayList<Double> array){
double[] newArray = convertArray(array);
double standardDeviation = StandardDeviationSample(newArray);
return standardDeviation;
}
/**
* Sub-function to calculate the variance of the population
* @param array data array for which the variance is to be found
* @return variance of the data array
*/
public static double VariancePopulation(double[] array){
double average = meanArithmetic(array);
//Calculate sum of differences
double sum = 0;
for(int i=0; i<array.length; i++){
sum = sum + Math.pow((array[i] - average), 2);
}
//Calculate total number in the set
double ctr = (double) array.length;
if(ctr == 0){//fix divide by zero errors
ctr = 1;
}
double variance = sum/ctr;
return variance;
}
/**
* Sub-function to calculate the variance of the population
* @param array data array for which the variance is to be found
* @return variance of the data array
*/
public static double VariancePopulation(ArrayList<Double> array){
double[] newArray = convertArray(array);
double variance = VariancePopulation(newArray);
return variance;
}
/**
* Sub-function to calculate the variance of the population, variance = [1/(n-1)] * sum[(value - average)^2]
* @param array data array for which the variance is to be found
* @return variance of the data array
*/
public static double VarianceSample(double[] array){
double average = meanArithmetic(array);
//Calculate sum of differences
double sum = 0;
for(int i=0; i<array.length; i++){
sum = sum + Math.pow((array[i] - average), 2);
}
//Calculate total number in the set
double denominator = 0;
//fix divide by zero errors
if((array.length-1) <= 0){
denominator = 1;
}else{
denominator = array.length - 1;
}
//Calculate variance
double variance = sum/denominator;
return variance;
}
/**
* Sub-function to calculate the variance of the population
* @param array data array for which the variance is to be found
* @return variance of the data array
*/
public static double VarianceSample(ArrayList<Double> array){
double[] newArray = convertArray(array);
double variance = VarianceSample(newArray);
return variance;
}
/**
* Sub-function to calculate the coefficient of variation of a dataset (Standard deviation / average)
* @param array input list data for coefficient of variation
* @return coefficient of variation of the dataset.
*/
public static double CoefficientOfVariation(double[] array){
//Calculate the average and standard deviation for the coefficient of varience
double average = meanArithmetic(array);
double stDev = StandardDeviationSample(array);
double coefVar = stDev/average;
return coefVar;
}
/**
* Sub-function to calculate the coefficient of variation of a dataset (Standard deviation / average)
* @param array input list data for coefficient of variation
* @return coefficient of variation of the dataset.
*/
public static double CoefficientOfVariation(ArrayList<Double> array){
double[] newArray = convertArray(array);
double coefVar = CoefficientOfVariation(newArray);
return coefVar;
}
/**
* Sub-function to calculate the covariance of two datasets
* @param xData input list of x data
* @param yData input list of y data
* @return covariance of variation of the dataset.
* @throws IOException
*/
public static double Covariance(double[] xData, double[] yData) throws IOException{
//Check if arrays are the same size
if(xData.length != yData.length){
throw(new IOException("Data arrays must be the same size to perform this statistic. X data size:\t" +
xData.length + "\tY data size:\t" + yData.length));
}
double N = xData.length;
//Calculate the average of the two datasets
double xBar = meanArithmetic(xData);
double yBar = meanArithmetic(yData);
//Sum (Xi - Xbar) * (Yi - Ybar)
double sum = 0;
for(int i=0; i<N; i++){
sum = sum + ((xData[i] - xBar) * (yData[i] - yBar));
}
double covariance = sum / (N - 1);
return covariance;
}
/**
* Sub-function to calculate the covariance of two datasets
* @param xArray input list of x data
* @param yArray input list of y data
* @return covariance of variation of the dataset.
* @throws IOException
*/
public static double Covariance(ArrayList<Double> xArray, ArrayList<Double> yArray) throws IOException{
double[] newXarray = convertArray(xArray);
double[] newYarray = convertArray(yArray);
double covariance = Covariance(newXarray, newYarray);
return covariance;
}
/**
* Sub-function to calculate the skewness of a dataset
* @param array input list data for skewness
* @return skewness of the dataset.
*/
public static double SkewnessPopulation(double[] array){
//Get the average and standard deviation for use in the skewness formula
double average = meanArithmetic(array);
double stDev = StandardDeviationSample(array);
//Create list of values to compute the expected value (average) of in order to get the skewness
double[] list = new double[array.length];
for(int i=0; i<array.length; i++){
list[i] = Math.pow(((array[i] - average)/stDev), 3);
}
double skewness = meanArithmetic(list);
return skewness;
}
/**
* Sub-function to calculate the skewness of a dataset
* @param array input list data for skewness
* @return skewness of the dataset.
*/
public static double SkewnessPopulation(ArrayList<Double> array){
double[] newArray = convertArray(array);
double skewness = SkewnessPopulation(newArray);
return skewness;
}
/**
* Sub-function to calculate the sample skewness (Fisher-Pearson skewness) of a dataset.
* Skewness = (n /((n-1)(n-2))) * sum{ ((x - average)/standard Deviation) ^ 3 }
* @param array input list data for skewness
* @return skewness of the dataset.
*/
public static double SkewnessSample(double[] array){
//Get the average and standard deviation for use in the skewness formula
double average = meanArithmetic(array);
double variance = VarianceSample(array);
double count = array.length;
if(count == 0){//fix divide by zero errors
count = 1;
}
//Create list of values to compute the expected value (average) of in order to get the skewness
double[] list = new double[array.length];
for(int i=0; i<array.length; i++){
list[i] = Math.pow((array[i] - average)/variance, 3);
}
double coefficient = count /( (count - 1)*(count - 2) );
double skewness = coefficient * sum(list);
return skewness;
}
/**
* Sub-function to calculate the sample skewness of a dataset.
* @param array input list data for skewness
* @return skewness of the dataset.
*/
public static double SkewnessSample(ArrayList<Double> array){
double[] newArray = convertArray(array);
double skewness = SkewnessSample(newArray);
return skewness;
}
/**
* Sub-function to calculate the sum of squares of x (Sxx) of a dataset.
* @param xData input list data for Sxx
* @return Sxx of the dataset.
*/
public static double Sxx(double[] xData){
double xBar = meanArithmetic(xData);
double sxx = 0;
for(int i=0; i<xData.length; i++){
sxx = sxx + Math.pow(xData[i] - xBar, 2);
}
return sxx;
}
/**
* Sub-function to calculate the sum of squares of x (Sxx) of a dataset.
* @param xArray input list data for Sxx
* @return Sxx of the dataset.
*/
public static double Sxx(ArrayList<Double> xArray){
double[] newXarray = convertArray(xArray);
double sxx = Sxx(newXarray);
return sxx;
}
/**
* Sub-function to calculate the sum of cross products (Sxy) of two datasets.
* @param xArray input list of x data for Sxy
* @param yArray input list of y data for Sxy
* @return Sxx of the datasets.
* @throws java.io.IOException
*/
public static double Sxy(double[] xArray, double[] yArray) throws IOException{
//Check if arrays are the same size
if(xArray.length != yArray.length){
throw(new IOException("Data arrays must be the same size to perform this statistic. X data size:\t" +
xArray.length + "\tY data size:\t" + yArray.length));
}
double xBar = meanArithmetic(xArray);
double yBar = meanArithmetic(yArray);
double sxy = 0;
for(int i=0; i<xArray.length; i++){
sxy = sxy + (xArray[i] - xBar)*(yArray[i] - yBar);
}
return sxy;
}
/**
* Sub-function to calculate the sum of cross products (Sxy) of two datasets.
* @param xArray input list of x data for Sxy
* @param yArray input list of y data for Sxy
* @return Sxx of the datasets.
* @throws java.io.IOException
*/
public static double Sxy(ArrayList<Double> xArray, ArrayList<Double> yArray) throws IOException{
double[] newXarray = convertArray(xArray);
double[] newYarray = convertArray(yArray);
double sxy = Sxy(newXarray, newYarray);
return sxy;
}
/**
* Sub-function to calculate the correlation coefficient (r) of two datasets.
* @param xArray input list of x data
* @param yArray input list of y data
* @return the correlation coefficient of the two data sets [r = Sxy / squareRoot(Sxx * Syy)]
* @throws java.io.IOException
*/
public static double CorrelationCoefficient(double[] xArray, double[] yArray) throws IOException{
//Check if arrays are the same size
if(xArray.length != yArray.length){
throw(new IOException("Data arrays must be the same size to perform this statistic. X data size:\t" +
xArray.length + "\tY data size:\t" + yArray.length));
}
double sxx = Sxx(xArray);
double syy = Sxx(yArray);
double sxy = Sxy(xArray, yArray);
double r = sxy / Math.pow(sxx*syy, 0.5);
return r;
}
/**
* Sub-function to calculate the correlation coefficient (r) of two datasets.
* @param xArray input list of x data
* @param yArray input list of y data
* @return the correlation coefficient of the two data sets [r = Sxy / squareRoot(Sxx * Syy)]
* @throws java.io.IOException
*/
public static double CorrelationCoefficient(ArrayList<Double> xArray, ArrayList<Double> yArray) throws IOException{
double[] newXarray = convertArray(xArray);
double[] newYarray = convertArray(yArray);
double r = CorrelationCoefficient(newXarray, newYarray);
return r;
}
/**
* Sub-function to calculate the R^2 (Rsquare) value of two datasets. Rsquare is the coefficient of determination fraction of the variance explained by regression
* @param xArray input list of x data
* @param yArray input list of y data
* @return the Rsquare of the two data sets [r = 1 - See/Syy]
* @throws java.io.IOException
*/
public static double Rsquare(double[] xArray, double[] yArray) throws IOException{
//Check if arrays are the same size
if(xArray.length != yArray.length){
throw(new IOException("Data arrays must be the same size to perform this statistic. X data size:\t" +
xArray.length + "\tY data size:\t" + yArray.length));
}
double sxx = Sxx(xArray);
double syy = Sxx(yArray);
double n = xArray.length;
if(n == 0){//fix divide by zero errors
n = 1;
}
double sxy = Sxy(xArray, yArray);
double b1 = sxy / sxx;
double Ssquare = (syy - b1*sxx)/(n-2);
double rSquare = (syy - Ssquare*(n - 2))/syy;
return rSquare;
}
/**
* Sub-function to calculate the R^2 (Rsquare) value of two datasets. Rsquare is the coefficient of determination fraction of the variance explained by regression
* @param xArray input list of x data for Sxy
* @param yArray input list of y data for Sxy
* @return the Rsquare of the two data sets [r = 1 - See/Syy]
* @throws java.io.IOException
*/
public static double Rsquare(ArrayList<Double> xArray, ArrayList<Double> yArray) throws IOException{
double[] newXarray = convertArray(xArray);
double[] newYarray = convertArray(yArray);
double rSquare = Rsquare(newXarray, newYarray);
return rSquare;
}
/**
* Computes the sum of squared errors for a set of give error values
* @param array array of difference values (y - y_hat)
* @return the sum of squared errors, sum(error_i ^ 2)
*/
public static double SSE(double[] array){
double sum = 0;
for(int i=0; i<array.length;i++){
sum = sum + Math.pow(array[i], 2);
}
return sum;
}
/**
* Computes the Likelihood function for a set of give error values
* @param array array of difference values (y - y_hat)
* @return the value of the likelihood function LH = product( [1/sqrt(2*pi*sigma_errors^2)] * exp [-(error^2) / (2*sigma_errors^2)]
*/
public static double LF(double[] array){
//Compute the variance of the errors
double sigma_e2 = VarianceSample(array);
//Calculate the likelihood function for the array and the varience
double LH = 1;
for(int i=0; i<array.length; i++){
LH = LH * ( (Math.pow(2*Math.PI*sigma_e2, -0.5)) * Math.exp(-Math.pow(array[i], 2) / (2*sigma_e2)) );
}
return LH;
}
/**
* Computes the Log-Likelihood function for a set of give error values
* @param array array of difference values (y - y_hat)
* @return the value of the likelihood function, LLH = (-n/2)*ln(2*pi) - 1/2*ln(sigma_errors ^ 2n) - 1/2*(sigma_errors ^ -2)*sum(errors[i] ^ 2)
*/
public static double LLF(double[] array){
//Compute the standard deviation of the errors
double N = array.length;
double sigma_e = StandardDeviationSample(array);
//Calculate the log-likelihood function for the array and the standard deviation
double sse = SSE(array);
Double part1 = (N * Math.log(2*Math.PI) / (-2));
Double part2 = (Math.log(Math.pow(sigma_e, 2*N)) / (2));
Double part3 = (Math.pow(sigma_e, -2) / (2));
//Check if the log/powers calculated any infinite values
if(part2.isInfinite()){
part2 = 1.0;
}
if(part3.isInfinite()){
part3 = 1.0;
}
double LLH = part1 - part2 - (part3 * sse);
//System.out.println("LLF Results: "+N +"\t"+sigma_e+"\t"+sse+"\t"+LLH);
return LLH;
}
/**
* Computes the Akaike Information Criterion (AIC) value for a given dataset using the Log-Likelihood function
* and number of parameters of the model as a goodness of fit test
* @param array array of difference values (y - y_hat) or (actual - predicted)
* @param numberOfParams the number of parameters used in the model (AR(p) or ARMA(p,q)) to predict future data
* @return the value of AIC for the given errors and parameters
*/
public static double AIC(double[] array, int numberOfParams){
//Compute the log-likelihood function
double llf = LLF(array);
//Compute the value of aic
double aic = 2*numberOfParams - 2*llf;
return aic;
}
/**
* Computes the Bayesian Information Criterion (BIC) value for a given dataset using the Log-Likelihood function
* and number of parameters of the model as a goodness of fit test
* @param array array of difference values (y - y_hat) or (actual - predicted)
* @param numberOfParams the number of parameters used in the model (AR(p) or ARMA(p,q)) to predict future data
* @return the value of BIC for the given errors and parameters
*/
public static double BIC(double[] array, int numberOfParams){
//Compute the log-likelihood function
double llf = LLF(array);
double N = array.length;
//Compute the value of bic
double bic = 2*numberOfParams*Math.log(N) - 2*llf;
return bic;
}
/**
* Computes the Nash-Sutcliffe Model Efficiency Coefficient, note that the provided data must be match lists, aka
* the value of observed[i] must be at the same date as modeled[i] for the equation to work
* @param observed array of observed values, sorted by observation date
* @param modeled array of modeled values, sorted by model date, paired to the same dates as the above observed dates
* @return
* @throws java.io.IOException
*/
public static double NashSutcliffe(double[] observed, double[] modeled) throws IOException{
//Check if arrays are the same size
if(observed.length != modeled.length){
throw(new IOException("Data arrays must be the same size to perform this statistic. Observed data size:\t" +
observed.length + "\tModeled data size:\t" + modeled.length));
}
double observed_ave = meanArithmetic(observed);
double numerator = 0;
double denominator = 0;
for(int i=0; i<observed.length; i++){
numerator = numerator + (observed[i] - modeled[i])*(observed[i] - modeled[i]);
denominator = denominator + (observed[i] - observed_ave)*(observed[i] - observed_ave);
}
double E = 1 - (numerator/denominator);
return E;
}
/**
* Computes the Nash-Sutcliffe Model Efficiency Coefficient, note that the provided data must be match lists, aka
* the value of observed[i] must be at the same date as modeled[i] for the equation to work
* @param observed array of observed values, sorted by observation date
* @param modeled array of modeled values, sorted by model date, paired to the same dates as the above observed dates
* @return
* @throws java.io.IOException
*/
public static double NashSutcliffe(ArrayList<Double> observed, ArrayList<Double> modeled) throws IOException{
double[] newObsArray = convertArray(observed);
double[] newModArray = convertArray(modeled);
double E = NashSutcliffe(newObsArray, newModArray);
return E;
}
/**
* Calculates the Kendall Correlation Coefficient (tau) based on the provided paired data
* @param pairedData a list of only y values which belong to a sorted (by magnitude of x) list of paired x-y data in the Mann-Kendall test.
* @return the Mann-Kendall Correlation Coefficient
*/
public static double KendallCorrelationCoefficient(ArrayList<Double> pairedData){
//Compare ordered pairs such that i > j
int M = 0, P = 0;
for(int j=0; j<pairedData.size(); j++){
double yValue_j = pairedData.get(j);
for(int i=(j+1); i<pairedData.size(); i++){//Starts at i = j+1 to enforce i > j at all times
double yValue_i = pairedData.get(i);
if(yValue_i > yValue_j){
P++;
}else if(yValue_i < yValue_j){
M++;
}
}
}
//Calculate Kendall Tau
double S = P - M;
double n = pairedData.size();
double tau = S / (n * (n-1) / 2);
return tau;
}
/**
* Computes the Mean Relative Error, note that the provided data must be match lists, aka
* the value of observed[i] must be at the same date as modeled[i] for the equation to work
* @param observed array of observed values, sorted by observation date
* @param modeled array of modeled values, sorted by model date, paired to the same dates as the above observed dates
* @return
* @throws java.io.IOException
*/
public static double MeanRelativeError(double[] observed, double[] modeled) throws IOException{
//Check if arrays are the same size
if(observed.length != modeled.length){
throw(new IOException("Data arrays must be the same size to perform this statistic. Observed data size:\t" +
observed.length + "\tModeled data size:\t" + modeled.length));
}
double sum = 0;
for(int i=0; i<observed.length; i++){
sum += Math.abs( (observed[i] - modeled[i]) / observed[i] );
}
double mre = (100.0/observed.length) * sum;
return mre;
}
/**
* Computes the Mean Relative Error, note that the provided data must be match lists, aka
* the value of observed[i] must be at the same date as modeled[i] for the equation to work
* @param observed array of observed values, sorted by observation date
* @param modeled array of modeled values, sorted by model date, paired to the same dates as the above observed dates
* @return
* @throws java.io.IOException
*/
public static double MeanRelativeError(ArrayList<Double> observed, ArrayList<Double> modeled) throws IOException{
double[] newObsArray = convertArray(observed);
double[] newModArray = convertArray(modeled);
double mre = MeanRelativeError(newObsArray, newModArray);
return mre;
}
/**
* Computes the Percent Bias (PBIAS), note that the provided data must be match lists, aka
* the value of observed[i] must be at the same date as modeled[i] for the equation to work
* @param observed array of observed values, sorted by observation date
* @param modeled array of modeled values, sorted by model date, paired to the same dates as the above observed dates
* @return
* @throws java.io.IOException
*/
public static double PercentBias(double[] observed, double[] modeled) throws IOException{
//Check if arrays are the same size
if(observed.length != modeled.length){
throw(new IOException("Data arrays must be the same size to perform this statistic. Observed data size:\t" +
observed.length + "\tModeled data size:\t" + modeled.length));
}
double numerator = 0;
double denominator = 0;
for(int i=0; i<observed.length; i++){
numerator += (observed[i] - modeled[i]) * 100;
denominator += observed[i];
}
double pbias = numerator/denominator;
return pbias;
}
/**
* Computes the Percent Bias (PBIAS), note that the provided data must be match lists, aka
* the value of observed[i] must be at the same date as modeled[i] for the equation to work
* @param observed array of observed values, sorted by observation date
* @param modeled array of modeled values, sorted by model date, paired to the same dates as the above observed dates
* @return
* @throws java.io.IOException
*/
public static double PercentBias(ArrayList<Double> observed, ArrayList<Double> modeled) throws IOException{
double[] newObsArray = convertArray(observed);
double[] newModArray = convertArray(modeled);
double pbias = PercentBias(newObsArray, newModArray);
return pbias;
}
}