/**
* This file is part of General Entity Annotator Benchmark.
*
* General Entity Annotator Benchmark is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* General Entity Annotator Benchmark is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with General Entity Annotator Benchmark. If not, see <http://www.gnu.org/licenses/>.
*/
package org.aksw.gerbil.evaluate.impl;
import java.util.List;
import org.aksw.gerbil.evaluate.DoubleEvaluationResult;
import org.aksw.gerbil.evaluate.EvaluationResult;
import org.aksw.gerbil.evaluate.EvaluationResultContainer;
import org.aksw.gerbil.evaluate.Evaluator;
import org.aksw.gerbil.matching.EvaluationCounts;
import org.aksw.gerbil.matching.MatchingsCounter;
import org.aksw.gerbil.transfer.nif.Marking;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FMeasureCalculator<T extends Marking> implements Evaluator<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(FMeasureCalculator.class);
public static final String MACRO_F1_SCORE_NAME = "Macro F1 score";
public static final String MACRO_PRECISION_NAME = "Macro Precision";
public static final String MACRO_RECALL_NAME = "Macro Recall";
public static final String MICRO_F1_SCORE_NAME = "Micro F1 score";
public static final String MICRO_PRECISION_NAME = "Micro Precision";
public static final String MICRO_RECALL_NAME = "Micro Recall";
protected MatchingsCounter<T> matchingsCounter;
public FMeasureCalculator(MatchingsCounter<T> matchingsCounter) {
super();
this.matchingsCounter = matchingsCounter;
}
@Override
public void evaluate(List<List<T>> annotatorResults, List<List<T>> goldStandard,
EvaluationResultContainer results) {
EvaluationCounts counts[] = generateMatchingCounts(annotatorResults, goldStandard);
results.addResults(calculateMicroFMeasure(counts));
results.addResults(calculateMacroFMeasure(counts));
}
protected EvaluationCounts[] generateMatchingCounts(List<List<T>> annotatorResults, List<List<T>> goldStandard) {
EvaluationCounts counts[] = new EvaluationCounts[annotatorResults.size()];
for (int i = 0; i < counts.length; ++i) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("doc " + i + "|||||||||");
}
counts[i] = matchingsCounter.countMatchings(annotatorResults.get(i), goldStandard.get(i));
}
return counts;
}
protected EvaluationResult[] calculateMicroFMeasure(EvaluationCounts counts[]) {
return calculateMicroFMeasure(counts, MICRO_PRECISION_NAME, MICRO_RECALL_NAME, MICRO_F1_SCORE_NAME);
}
protected EvaluationResult[] calculateMicroFMeasure(EvaluationCounts counts[], String precisionName,
String recallName, String f1ScoreName) {
EvaluationCounts sums = new EvaluationCounts();
for (int i = 0; i < counts.length; ++i) {
sums.add(counts[i]);
}
double measures[] = calculateMeasures(sums);
return new EvaluationResult[] { new DoubleEvaluationResult(precisionName, measures[0]),
new DoubleEvaluationResult(recallName, measures[1]),
new DoubleEvaluationResult(f1ScoreName, measures[2]) };
}
protected EvaluationResult[] calculateMacroFMeasure(EvaluationCounts counts[]) {
return calculateMacroFMeasure(counts, MACRO_PRECISION_NAME, MACRO_RECALL_NAME, MACRO_F1_SCORE_NAME);
}
protected EvaluationResult[] calculateMacroFMeasure(EvaluationCounts counts[], String precisionName,
String recallName, String f1ScoreName) {
double avgs[] = new double[3];
double measures[];
for (int i = 0; i < counts.length; ++i) {
measures = calculateMeasures(counts[i]);
avgs[0] += measures[0];
avgs[1] += measures[1];
avgs[2] += measures[2];
}
avgs[0] /= counts.length;
avgs[1] /= counts.length;
avgs[2] /= counts.length;
return new EvaluationResult[] { new DoubleEvaluationResult(precisionName, avgs[0]),
new DoubleEvaluationResult(recallName, avgs[1]), new DoubleEvaluationResult(f1ScoreName, avgs[2]) };
}
private double[] calculateMeasures(EvaluationCounts counts) {
double precision, recall, F1_score;
if (counts.truePositives == 0) {
if ((counts.falsePositives == 0) && (counts.falseNegatives == 0)) {
// If there haven't been something to find and nothing has been
// found --> everything is great
precision = 1.0;
recall = 1.0;
F1_score = 1.0;
} else {
// The annotator found no correct ones, but made some mistake
// --> that is bad
precision = 0.0;
recall = 0.0;
F1_score = 0.0;
}
} else {
precision = (double) counts.truePositives / (double) (counts.truePositives + counts.falsePositives);
recall = (double) counts.truePositives / (double) (counts.truePositives + counts.falseNegatives);
F1_score = (2 * precision * recall) / (precision + recall);
}
return new double[] { precision, recall, F1_score };
}
}