package org.neuroph.eval.classification;
import static java.lang.Math.sqrt;
import java.util.ArrayList;
import java.util.List;
/**
* Container class for all metrics which use confusion matrix for their computation
*
* Based on:
* http://java-ml.sourceforge.net/api/0.1.7/net/sf/javaml/classification/evaluation/PerformanceMeasure.html
* http://sourceforge.net/p/java-ml/java-ml-code/ci/a25ddde7c3677da44e47a643f88e32e2c8bbc32f/tree/net/sf/javaml/classification/evaluation/PerformanceMeasure.java
*
* http://en.wikipedia.org/wiki/Matthews_correlation_coefficient
*
*/
public final class ClassificationMetrics {
double truePositive;
double trueNegative;
double falsePositive;
double falseNegative;
double correlationCoefficient;
double total;
String classLabel; // where is this used?
/**
* Constructs a new measure using arguments
* TODO: add class to which measure corresponds?
*
* @param truePositive
* @param trueNegative
* @param falsePositive
* @param falseNegative
*/
public ClassificationMetrics(int truePositive, int trueNegative, int falsePositive, int falseNegative) {
this.truePositive = truePositive;
this.trueNegative = trueNegative;
this.falsePositive = falsePositive;
this.falseNegative = falseNegative;
this.total = falseNegative + falsePositive + trueNegative + truePositive;
}
/**
* Returns class label for
* @return class labels
*/
public String getClassLabel() {
return classLabel;
}
public void setClassLabel(String classLabel) {
this.classLabel = classLabel;
}
/**
* Calculate and return classification accuracy measure.
* A number of correct predictions made divided by the total number of predictions made
* a = ( tp + tn ) / n
*
* @return classification accuracy
*/
public double getAccuracy() {
return (truePositive + trueNegative) / total;
}
/**
* A number of wrong predictions made divided by the total number of predictions made.
* Also error = 1 - accuracy
* @return
*/
public double getErrorRate() {
return (falsePositive + falseNegative) / total;
}
/**
* Calculate and return classification precision measure.
* A number of correctly classified positive examples divided by the total number of examples that are classified as positive
* Also known as positive predictive value PPV
* @return classification precision measure
*/
public double getPrecision() {
return truePositive / (truePositive + falsePositive);
}
/**
* Calculate and return classification sensitivity (recall, true positive rate)
* number of correctly classified positive examples divided by the total number of actual positive examples
* @return
*/
public double getSensitivity() {
return truePositive / (truePositive + falseNegative);
}
public double getRecall() {
return getSensitivity();
}
/**
* Specifity , true negative rate
*/
public double getSpecificity() {
return trueNegative / (trueNegative + falsePositive);
}
/**
* Returns total number of classifications.
* @return total number of classifications
*/
public double getTotal() {
return total;
}
public double getFalsePositiveRate() {
return falsePositive / (falsePositive + trueNegative);
}
//False negative rate,
public double getFalseNegativeRate() {
return falseNegative / (falseNegative + truePositive);
}
public double getFalseDiscoveryRate() {
return falsePositive / (truePositive + falsePositive);
}
// http://en.wikipedia.org/wiki/Matthews_correlation_coefficient
// measure of the quality of binary (two-class) classifications. It takes into account true and false positives and negatives and is generally regarded as a balanced measure which can be used even if the classes are of very different sizes.
public double getMatthewsCorrelationCoefficient() {
return (truePositive * trueNegative - falsePositive * falseNegative) /
(sqrt((truePositive + falsePositive) * (truePositive + falseNegative) * (trueNegative + falsePositive) * (trueNegative + falseNegative)));
}
/**
* Calculates F-score for beta equal to 1.
*
* @return f-score
*/
public double getFMeasure() {
return getFMeasure(1);
}
/**
* Returns the F-score. When recall and precision are zero, this method will
* return 0.
*
* @param beta
* @return f-score
*/
public double getFMeasure(int beta) {
double f = ((beta * beta + 1) * getPrecision() * getSensitivity())
/ (double)(beta * beta * getPrecision() + getSensitivity());
if (Double.isNaN(f))
return 0;
else
return f;
}
public double getQ9() {
if (truePositive + falseNegative == 0) {
return (trueNegative - falsePositive) / (trueNegative + falsePositive);
} else if (trueNegative + falsePositive == 0) {
return (truePositive - falseNegative) / (truePositive + falseNegative);
} else
return 1 - Math.sqrt(2)
* Math.sqrt(Math.pow(falseNegative / (truePositive + falseNegative), 2)
+ Math.pow(falsePositive / (trueNegative + falsePositive), 2));
}
public double getBalancedClassificationRate() {
if (trueNegative == 0 && falsePositive == 0)
return truePositive / (truePositive + falseNegative);
if (truePositive == 0 && falseNegative == 0)
return trueNegative / (trueNegative + falsePositive);
return 0.5 * (truePositive / (truePositive + falseNegative) + trueNegative / (trueNegative + falsePositive));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Class: "+classLabel).append("\n");
sb.append("Total items: ").append(getTotal()).append("\n");
sb.append("True positive:").append(truePositive).append("\n");
sb.append("True negative:").append(trueNegative).append("\n");
sb.append("False positive:").append(falsePositive).append("\n");
sb.append("False negative:").append(falseNegative).append("\n");
sb.append("Accuracy (ACC): ").append(getAccuracy()).append("\n");
sb.append("Sensitivity or true positive rate (TPR): ").append(getSensitivity()).append("\n");
sb.append("Specificity (SPC) or true negative rate (TNR): ").append(getSpecificity()).append("\n");
sb.append("Fall-out or false positive rate (FPR): ").append(getFalsePositiveRate()).append("\n");
sb.append("False negative rate (FNR): ").append(getFalseNegativeRate()).append("\n");
sb.append("Precision or positive predictive value (PPV): ").append(getPrecision()).append("\n");
sb.append("Recall: ").append(getSensitivity()).append("\n");
sb.append("F-measure: ").append(getFMeasure()).append("\n");
sb.append("False discovery rate (FDR): ").append(getFalseDiscoveryRate()).append("\n");
sb.append("Matthews correlation Coefficient (MCC): ").append(getMatthewsCorrelationCoefficient()).append("\n");
return sb.toString();
}
public static class Stats {
public double accuracy=0;
public double precision=0;
public double recall=0;
public double fScore=0;
public double mserror=0;
public double correlationCoefficient = 0;
@Override
public String toString() {
return "Stats{" + "accuracy=" + accuracy + ", precision=" + precision + ", recall=" + recall + ", fScore=" + fScore + ", mserror=" + mserror + ", corelationCoefficient=" + correlationCoefficient + '}';
}
}
public static ClassificationMetrics[] createFromMatrix(ConfusionMatrix confusionMatrix) {
// Create Classification measure for each class
// Ovde rezdvojiti binary i multi
int classCount = confusionMatrix.getClassCount();
if (classCount == 2) { // binary classification
ClassificationMetrics[] measures = new ClassificationMetrics[1];
String[] classLabels = confusionMatrix.getClassLabels();
int tp = confusionMatrix.get(0, 0);
int tn = confusionMatrix.get(1, 1);
int fp = confusionMatrix.get(1, 0); // FalsePositive
int fn = confusionMatrix.get(0, 1); // FalseNegative
measures[0] = new ClassificationMetrics(tp, tn, fp, fn);
measures[0].setClassLabel(classLabels[0]);
return measures;
} else { // multiclass classification
ClassificationMetrics[] measures = new ClassificationMetrics[classCount];
String[] classLabels = confusionMatrix.getClassLabels();
for(int clsIdx=0; clsIdx classLabels = new ArrayList<>();
ClassificationMetrics.Stats average = new ClassificationMetrics.Stats();
double count = 0;
for (ClassificationMetrics cm : results) {
average.accuracy += cm.getAccuracy();
average.precision += cm.getPrecision();
average.recall += cm.getSensitivity();
average.fScore += cm.getFMeasure();
// average.mserror += er.getMeanSquareError();
if(!classLabels.contains(cm.getClassLabel()))
classLabels.add(cm.getClassLabel());
}
count++;
count = count * classLabels.size(); // * classes count
average.accuracy = average.accuracy / count;
average.precision = average.precision / count;
average.recall = average.recall / count;
average.fScore = average.fScore / count;
average.mserror = average.mserror / count;
return average;
}
/**
*
* @param results list of different metric results computed on different sets of data
* @return maximum metrics computed different MetricResults
*/
// public static ClassificationMetrics maxFromMultipleRuns(List results) {
// double maxAccuracy = 0;
// double maxError = 0;
// double maxPrecision = 0;
// double maxRecall = 0;
// double maxFScore = 0;
//
// for (ClassificationMetrics metricResult : results) {
// maxAccuracy = Math.max(maxAccuracy, metricResult.getAccuracy());
// maxError = Math.max(maxError, metricResult.getError());
// maxPrecision = Math.max(maxPrecision, metricResult.getPrecision());
// maxRecall = Math.max(maxRecall, metricResult.getRecall());
// maxFScore = Math.max(maxFScore, metricResult.getFScore());
// }
//
// ClassificationMetrics averageMetricsResult = new ClassificationMetrics();
//
// averageMetricsResult.accuracy = maxAccuracy;
// averageMetricsResult.error = maxError;
// averageMetricsResult.precision = maxPrecision;
// averageMetricsResult.recall = maxRecall;
// averageMetricsResult.fScore = maxFScore;
//
// return averageMetricsResult;
// }
// private static double[] createFScoresForEachClass(double[] precisions, double[] recalls) {
// double[] fScores = new double[precisions.length];
//
// for (int i = 0; i < precisions.length; i++) {
// fScores[i] = 2 * (precisions[i] * recalls[i]) / (precisions[i] + recalls[i]);
// }
//
// return fScores;
// }
// private static double safelyDivide(double x, double y) {
// double divisor = x == 0.0 ? 1 : x;
// double divider = y == 0.0 ? 1.0 : y;
// return divisor / divider;
// }
}
Ads help maintain this website.