/*
* Copyright 2012 DBpedia Spotlight Development Team
*
* 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.
*
* Check our project website for information on how to acknowledge the authors and how to contribute to the project: http://spotlight.dbpedia.org
*/
package org.dbpedia.spotlight.evaluation;
import com.aliasi.sentences.IndoEuropeanSentenceModel;
import net.sf.json.JSONException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dbpedia.spotlight.exceptions.ConfigurationException;
import org.dbpedia.spotlight.exceptions.InitializationException;
import org.dbpedia.spotlight.exceptions.SpottingException;
import org.dbpedia.spotlight.model.SpotlightConfiguration;
import org.dbpedia.spotlight.model.SurfaceForm;
import org.dbpedia.spotlight.model.SurfaceFormOccurrence;
import org.dbpedia.spotlight.model.Text;
import org.dbpedia.spotlight.spot.*;
import org.dbpedia.spotlight.spot.cooccurrence.classification.SpotClass;
import org.dbpedia.spotlight.spot.cooccurrence.training.AnnotatedDataset;
import org.dbpedia.spotlight.spot.cooccurrence.training.AnnotatedSurfaceFormOccurrence;
import org.dbpedia.spotlight.spot.lingpipe.LingPipeSpotter;
import org.dbpedia.spotlight.spot.opennlp.OpenNLPChunkerSpotter;
import org.dbpedia.spotlight.spot.opennlp.ProbabilisticSurfaceFormDictionary;
import org.dbpedia.spotlight.spot.opennlp.SurfaceFormDictionary;
import org.dbpedia.spotlight.tagging.lingpipe.LingPipeFactory;
import org.dbpedia.spotlight.tagging.lingpipe.LingPipeTaggedTokenProvider;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.*;
/**
* Evaluator for {@link org.dbpedia.spotlight.spot.Spotter}s (and spot selectors).
*
* @author pablomendes (based on Spotter Evaluator from Joachim Daiber, modified for precision/recall calculations)
* @author Joachim Daiber
*/
public class SpotterEvaluatorPrecisionRecall {
private final static Log LOG = LogFactory.getLog(SpotterEvaluatorPrecisionRecall.class);
public static void main(String[] args) throws IOException, JSONException, ConfigurationException, InitializationException, org.json.JSONException {
SpotlightConfiguration configuration = new SpotlightConfiguration("conf/dev.properties");
LingPipeFactory lingPipeFactory = new LingPipeFactory(new File(configuration.getTaggerFile()), new IndoEuropeanSentenceModel());
LOG.info("Reading gold standard.");
AnnotatedDataset evaluationCorpus =
new AnnotatedDataset(new File("/home/pablo/eval/csaw/original"),
AnnotatedDataset.Format.CSAW, lingPipeFactory);
LOG.info(String.format("Read %s annotations.",evaluationCorpus.getInstances().size()));
/**
* Base:
*/
SelectorResult baseResult = getDatasetBaseResult(evaluationCorpus);
LOG.info(baseResult);
LOG.info("Reformatting.");
Map<SurfaceFormOccurrence, AnnotatedSurfaceFormOccurrence> goldSurfaceFormOccurrences = new HashMap<SurfaceFormOccurrence, AnnotatedSurfaceFormOccurrence>();
for(AnnotatedSurfaceFormOccurrence annotatedSurfaceFormOccurrence : evaluationCorpus.getInstances()) {
SurfaceFormOccurrence sfo = annotatedSurfaceFormOccurrence.toSurfaceFormOccurrence();
goldSurfaceFormOccurrences.put(sfo, annotatedSurfaceFormOccurrence);
//goldSurfaceFormOccurrences.put(getNameVariation(sfo), annotatedSurfaceFormOccurrence);
}
List<Text> documents = evaluationCorpus.getTexts();
evaluate(documents, goldSurfaceFormOccurrences, baseResult, lingPipeFactory, configuration);
LOG.info("Done.");
}
private static void evaluate(List<Text> documents,
Map<SurfaceFormOccurrence, AnnotatedSurfaceFormOccurrence> goldSurfaceFormOccurrences,
SelectorResult baseResult,
LingPipeFactory lingPipeFactory,
SpotlightConfiguration configuration) throws InitializationException, ConfigurationException {
StringBuffer latexTable = new StringBuffer();
/**
* No selection:
*/
File lexSpotterGoldFile = new File("/home/pablo/eval/csaw/gold/surfaceForms.set.spotterDictionary");
Spotter lexSpotterGold = new LingPipeSpotter(lexSpotterGoldFile , configuration.getAnalyzer());
lexSpotterGold.setName("\\lexspot{gold} ");
latexTable.append(getLatexTableRow(lexSpotterGold, documents, goldSurfaceFormOccurrences,baseResult));
File lexSpotterT3File = new File("/home/pablo/web/dbpedia36data/2.9.3/surface_forms-Wikipedia-TitRedDis.thresh3.spotterDictionary");
Spotter lexSpotterT3 = new LingPipeSpotter(lexSpotterT3File, configuration.getAnalyzer());
lexSpotterT3.setName("\\lexspot{>3} ");
latexTable.append(getLatexTableRow(lexSpotterT3, documents, goldSurfaceFormOccurrences,baseResult));
File lexSpotterT10File = new File("/home/pablo/web/dbpedia36data/2.9.3/surface_forms-Wikipedia-TitRedDis.uriThresh10.tsv.spotterDictionary");
Spotter lexSpotterT10 = new LingPipeSpotter(lexSpotterT10File, configuration.getAnalyzer());
lexSpotterT10.setName("\\lexspot{>10} ");
latexTable.append(getLatexTableRow(lexSpotterT10, documents, goldSurfaceFormOccurrences,baseResult));
File lexSpotterT75File = new File("/home/pablo/web/dbpedia36data/2.9.3/surface_forms-Wikipedia-TitRedDis.uriThresh75.tsv.spotterDictionary");
Spotter lexSpotterT75 = new LingPipeSpotter(lexSpotterT75File, configuration.getAnalyzer());
lexSpotterT75.setName("\\lexspot{>75} ");
latexTable.append(getLatexTableRow(lexSpotterT75, documents, goldSurfaceFormOccurrences,baseResult));
/**
* At least one noun:
*/
Spotter npSpotter = SpotterWithSelector.getInstance(
lexSpotterT3,
new AtLeastOneNounSelector(),
new LingPipeTaggedTokenProvider(lingPipeFactory)
);
npSpotter.setName("\\atLeastOneNoun");
latexTable.append(getLatexTableRow(npSpotter, documents, goldSurfaceFormOccurrences,baseResult));
/**
* OpenNLP Chunker
*/
String openNLPDir = "/data/spotlight/3.7/opennlp/english/";
String i18nLanguageCode = "en";
File stopwords = new File("data/stopwords/stopwords_en.txt");
SurfaceFormDictionary sfDictProbThreshGold = ProbabilisticSurfaceFormDictionary.fromLingPipeDictionaryFile(lexSpotterGoldFile,false);
Spotter onlpChunksSpotterGold = OpenNLPChunkerSpotter.fromDir(openNLPDir,i18nLanguageCode,sfDictProbThreshGold,stopwords);
onlpChunksSpotterGold.setName("\\joNPL{gold} ");
latexTable.append(getLatexTableRow(onlpChunksSpotterGold, documents, goldSurfaceFormOccurrences,baseResult));
//File sfDictThresh3 = new File("/home/pablo/workspace/spotlight/index/output/surfaceForms-fromOccs-thresh3-TRD.set");
//SurfaceFormDictionary sfDictProbThresh3 = ProbabilisticSurfaceFormDictionary.fromFile(sfDictThresh3, false);
SurfaceFormDictionary sfDictProbThresh3 = ProbabilisticSurfaceFormDictionary.fromLingPipeDictionaryFile(lexSpotterT3File,false);
Spotter onlpChunksSpotter3 = OpenNLPChunkerSpotter.fromDir(openNLPDir,i18nLanguageCode,sfDictProbThresh3,stopwords);
onlpChunksSpotter3.setName("\\joNPL{>3} ");
latexTable.append(getLatexTableRow(onlpChunksSpotter3, documents, goldSurfaceFormOccurrences,baseResult));
//File sfDictThresh10 = new File("/home/pablo/workspace/spotlight/index/output/surfaceForms-fromOccs-thresh10-TRD.set");
//SurfaceFormDictionary sfDictProbThresh10 = ProbabilisticSurfaceFormDictionary.fromFile(sfDictThresh10, false);
SurfaceFormDictionary sfDictProbThresh10 = ProbabilisticSurfaceFormDictionary.fromLingPipeDictionaryFile(lexSpotterT10File,false);
Spotter onlpChunksSpotter10 = OpenNLPChunkerSpotter.fromDir(openNLPDir,i18nLanguageCode,sfDictProbThresh10,stopwords);
onlpChunksSpotter10.setName("\\joNPL{>10} ");
latexTable.append(getLatexTableRow(onlpChunksSpotter10, documents, goldSurfaceFormOccurrences,baseResult));
//File sfDictThresh75 = new File("/home/pablo/workspace/spotlight/index/output/surfaceForms-fromOccs-thresh75.tsv");
//SurfaceFormDictionary sfDictProbThresh75 = ProbabilisticSurfaceFormDictionary.fromFile(sfDictThresh75, false);
SurfaceFormDictionary sfDictProbThresh75 = ProbabilisticSurfaceFormDictionary.fromLingPipeDictionaryFile(lexSpotterT75File,false);
Spotter onlpChunksSpotter75 = OpenNLPChunkerSpotter.fromDir(openNLPDir,i18nLanguageCode,sfDictProbThresh75,stopwords);
onlpChunksSpotter75.setName("\\joNPL{>75} ");
latexTable.append(getLatexTableRow(onlpChunksSpotter75, documents, goldSurfaceFormOccurrences,baseResult));
/**
* No common words.
*/
Spotter noCommonSpotter = SpotterWithSelector.getInstance(
lexSpotterT3,
new CoOccurrenceBasedSelector(configuration.getSpotterConfiguration()),
new LingPipeTaggedTokenProvider(lingPipeFactory)
);
noCommonSpotter.setName("\\cw ");
latexTable.append(getLatexTableRow(noCommonSpotter, documents, goldSurfaceFormOccurrences,baseResult));
/**
* Kea
*/
Spotter keaSpotter1 = new KeaSpotter("/data/spotlight/3.7/kea/keaModel-1-3-1", 1000, -1);
keaSpotter1.setName("$Kea_{>0}$ ");
latexTable.append(getLatexTableRow(keaSpotter1, documents, goldSurfaceFormOccurrences,baseResult));
// Spotter keaSpotter2 = new KeaSpotter("/data/spotlight/3.7/kea/keaModel-1-3-1", 1000, 0.015);
// keaSpotter2.setName("$Kea_{>0.015}$ ");
// latexTable.append(getLatexTableRow(keaSpotter2, documents, goldSurfaceFormOccurrences,baseResult));
//
// Spotter keaSpotter3 = new KeaSpotter("/data/spotlight/3.7/kea/keaModel-1-3-1", 1000, 0.075);
// keaSpotter3.setName("$Kea_{>0.075}$ ");
// latexTable.append(getLatexTableRow(keaSpotter3, documents, goldSurfaceFormOccurrences,baseResult));
//
// Spotter keaSpotter4 = new KeaSpotter("/data/spotlight/3.7/kea/keaModel-1-3-1", 1000, 0.15);
// keaSpotter4.setName("$Kea_{>0.15}$ ");
// latexTable.append(getLatexTableRow(keaSpotter4, documents, goldSurfaceFormOccurrences,baseResult));
//
// Spotter keaSpotter5 = new KeaSpotter("/data/spotlight/3.7/kea/keaModel-1-3-1", 1000, 0.3);
// keaSpotter5.setName("$Kea_{>0.3}$ ");
// latexTable.append(getLatexTableRow(keaSpotter5,documents,goldSurfaceFormOccurrences,baseResult));
/**
* NER
*/
Spotter neSpotter = new NESpotter(configuration.getSpotterConfiguration().getOpenNLPModelDir(), configuration.getI18nLanguageCode(), configuration.getSpotterConfiguration().getOpenNLPModelsURI());
neSpotter.setName("\\ner ");
latexTable.append(getLatexTableRow(neSpotter, documents, goldSurfaceFormOccurrences,baseResult));
/**
* NER+NP
*/
Spotter onlpSpotter = new OpenNLPNGramSpotter(configuration.getSpotterConfiguration().getOpenNLPModelDir()+ "/" + configuration.getLanguage().toLowerCase(), configuration.getI18nLanguageCode());
onlpSpotter.setName("\\nerNP ");
latexTable.append(getLatexTableRow(onlpSpotter, documents, goldSurfaceFormOccurrences,baseResult));
/**
* NER+NP+NG-CW
*/
Spotter onlpNoCommonSpotter = SpotterWithSelector.getInstance(
onlpSpotter,
new CoOccurrenceBasedSelector(configuration.getSpotterConfiguration()),
new LingPipeTaggedTokenProvider(lingPipeFactory)
);
onlpNoCommonSpotter.setName("NER+NP+NG-CW ");
latexTable.append(getLatexTableRow(onlpNoCommonSpotter, documents, goldSurfaceFormOccurrences,baseResult));
System.out.println(latexTable);
}
private static String getLatexTableRow(Spotter spotter,
List<Text> documents,
Map<SurfaceFormOccurrence, AnnotatedSurfaceFormOccurrence> goldSurfaceFormOccurrences,
SelectorResult baseResult) {
SelectorResult spotterBaseResult = evaluatePrecisionRecall(spotter, documents, goldSurfaceFormOccurrences);
//SelectorResult spotterBaseResult = evaluatePrecisionRecallWithNameVariation(spotter, documents, goldSurfaceFormOccurrences);
spotterBaseResult.printResult(baseResult);
return spotterBaseResult.getLatexResult(baseResult);
}
private static SelectorResult getSelectorResult(Spotter spotter, AnnotatedDataset evaluationCorpus) {
SelectorResult selectorResult = new SelectorResult(spotter.getName());
Set<SurfaceFormOccurrence> extractedSurfaceFormOccurrences = new HashSet<SurfaceFormOccurrence>();
long start = System.currentTimeMillis();
for(Text text : evaluationCorpus.getTexts())
try {
extractedSurfaceFormOccurrences.addAll(spotter.extract(text));
} catch (SpottingException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
long end = System.currentTimeMillis();
selectorResult.setTime(end - start);
for(AnnotatedSurfaceFormOccurrence annotatedSurfaceFormOccurrence : evaluationCorpus.getInstances()) {
SurfaceFormOccurrence sfo = annotatedSurfaceFormOccurrence.toSurfaceFormOccurrence();
if(extractedSurfaceFormOccurrences.contains(sfo)) {
SpotClass c = annotatedSurfaceFormOccurrence.getSpotClass();
if (c.equals(SpotClass.common))
selectorResult.addCommon();
else if (c.equals(SpotClass.valid))
selectorResult.addValid();
else if (c.equals(SpotClass.part))
selectorResult.addPart();
else {
System.out.println("The SpotClass instance is neither common nor valid nor part.");
}
} else {
selectorResult.addBlank();
//LOG.info(sfo);
}
selectorResult.addTotal();
}
return selectorResult;
}
/**
* Evaluates precision and recall for A and NA. Iterates over spots, checks if they are in gold.
*/
private static SelectorResult evaluatePrecisionRecall(Spotter spotter, List<Text> documents, Map<SurfaceFormOccurrence, AnnotatedSurfaceFormOccurrence> goldSurfaceFormOccurrences) {
SelectorResult selectorResult = new SelectorResult(spotter.getName());
PrintStream incorrectSpotsWriter = System.err;
try {
incorrectSpotsWriter = new PrintStream(new File("data",spotter.getName().trim().replaceAll("[^A-Za-z]","").concat(".incorrectSpots")));
} catch (FileNotFoundException e) {
LOG.error("Cannot write to incorrectSpots.");
}
Set<SurfaceFormOccurrence> found = new HashSet<SurfaceFormOccurrence>();
long start = System.currentTimeMillis();
for(Text text : documents) {
List<SurfaceFormOccurrence> extractedSurfaceFormOccurrences = null;
try {
extractedSurfaceFormOccurrences = spotter.extract(text);
} catch (SpottingException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
for (SurfaceFormOccurrence sfo: extractedSurfaceFormOccurrences) {
if(goldSurfaceFormOccurrences.containsKey(sfo)) {
found.add(sfo);
SpotClass c = goldSurfaceFormOccurrences.get(sfo).getSpotClass();
if (c.equals(SpotClass.common))
selectorResult.addCommon();
else if (c.equals(SpotClass.valid))
selectorResult.addValid();
else if (c.equals(SpotClass.part))
selectorResult.addPart();
else {
System.out.println("The SpotClass instance is neither common nor valid nor part.");
}
} else {
//Annotation not found
selectorResult.addBlank();
incorrectSpotsWriter.println(sfo.surfaceForm().name());
}
selectorResult.addTotal();
}
}
long end = System.currentTimeMillis();
selectorResult.setTime(end - start);
incorrectSpotsWriter.close();
PrintStream notFoundWriter = System.err;
try {
notFoundWriter = new PrintStream(new File("data",spotter.getName().trim().replaceAll("[^A-Za-z]","").concat(".correctSpotNotFound")));
} catch (FileNotFoundException e) {
LOG.error("Cannot write to notFoundWriter.");
}
for (SurfaceFormOccurrence correctSfo: goldSurfaceFormOccurrences.keySet()) {
if (!found.contains(correctSfo)) {
notFoundWriter.println(String.format("%s \t %s", correctSfo.surfaceForm().name(), correctSfo.textOffset()));
}
}
notFoundWriter.close();
return selectorResult;
}
/**
* Since CSAW disagrees with Wikipedia on the boundaries of entities, we created this method to alleviate the impact of this small detail.
* This method should only be used with dictionary-based spotters
* It checks if the spot starts with an article, and also tries it without the article
*/
private static SelectorResult evaluatePrecisionRecallWithNameVariation(Spotter spotter,
List<Text> documents,
Map<SurfaceFormOccurrence, AnnotatedSurfaceFormOccurrence> goldSurfaceFormOccurrences) {
SelectorResult selectorResult = new SelectorResult(spotter.getName());
PrintStream spotsWriter = System.err;
try {
spotsWriter = new PrintStream(new File("data",spotter.getName().trim().replaceAll("[^A-Za-z]","").concat(".spots.tsv")));
} catch (FileNotFoundException e) {
LOG.error("Cannot write to spotsWriter.");
}
for(Text text : documents) {
List<SurfaceFormOccurrence> extractedSurfaceFormOccurrences = null;
try {
extractedSurfaceFormOccurrences = spotter.extract(text);
} catch (SpottingException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
printSpots(spotsWriter,text,extractedSurfaceFormOccurrences);
for (SurfaceFormOccurrence sfo: extractedSurfaceFormOccurrences) {
if(goldSurfaceFormOccurrences.containsKey(sfo)) {
updateCount(goldSurfaceFormOccurrences.get(sfo), selectorResult);
} else { //Annotation not found. try variation
if (goldSurfaceFormOccurrences.containsKey(getNameVariation(sfo))) {
updateCount(goldSurfaceFormOccurrences.get(getNameVariation(sfo)), selectorResult);
} else { //Annotation still not found
selectorResult.addBlank();
}
}
selectorResult.addTotal();
}
}
spotsWriter.close();
return selectorResult;
}
private static void printSpots(PrintStream writer, Text text, List<SurfaceFormOccurrence> extractedSurfaceFormOccurrences) {
StringBuffer line = new StringBuffer();
line.append(text.text().hashCode());
line.append("\t");
for (SurfaceFormOccurrence sfo: extractedSurfaceFormOccurrences) {
line.append(sfo.surfaceForm());
line.append(":");
line.append(sfo.textOffset());
line.append(",");
}
line.append("\n");
writer.print(line.toString());
}
private static void updateCount(AnnotatedSurfaceFormOccurrence asfo, SelectorResult selectorResult) {
SpotClass c = asfo.getSpotClass();
if (c.equals(SpotClass.common))
selectorResult.addCommon();
else if (c.equals(SpotClass.valid))
selectorResult.addValid();
else if (c.equals(SpotClass.part))
selectorResult.addPart();
else {
System.out.println("The SpotClass instance is neither common nor valid nor part.");
}
}
private static SurfaceFormOccurrence getNameVariation(SurfaceFormOccurrence sfo) {
String sf = sfo.surfaceForm().name();
int offsetFromStart = 0;
int offsetFromEnd = 0;
if (sf.toLowerCase().startsWith("the ")) {
offsetFromStart = 4;
} else if (sf.toLowerCase().startsWith("a ")) {
offsetFromStart = 2;
} else if (sf.toLowerCase().startsWith("an ")) {
offsetFromStart = 3;
}
if (sf.toLowerCase().endsWith("[\\.\\,]")) {
offsetFromEnd = 1;
}
int end = sfo.surfaceForm().name().length()-1;
SurfaceForm variation = new SurfaceForm(sf.substring(offsetFromStart, end-offsetFromEnd).trim());
return new SurfaceFormOccurrence(variation, sfo.context(), sfo.textOffset()+offsetFromStart, sfo.provenance(), sfo.spotProb());
}
/**
* Retrieve the base distribution for valid and common results from the annotated
* dataset.
*
* @param evaluationCorpus corpus for evaluation
* @return base result
*/
private static SelectorResult getDatasetBaseResult(AnnotatedDataset evaluationCorpus) {
SelectorResult baseResult = new SelectorResult("Evaluation corpus base");
for(AnnotatedSurfaceFormOccurrence annotatedSurfaceFormOccurrence : evaluationCorpus.getInstances()) {
switch (annotatedSurfaceFormOccurrence.getSpotClass()){
case common:
baseResult.addCommon();
break;
case valid:
baseResult.addValid();
break;
case part:
baseResult.addPart();
break;
default:
baseResult.addBlank();
}
baseResult.addTotal();
}
return baseResult;
}
private static class SelectorResult {
private long time;
public SelectorResult(String name) {
this.name = name;
}
private String name;
int valid = 0;
int common = 0;
int part = 0;
int blank = 0; // number of spots that were neither valid, common or part
int total = 0; // should be the sum of valid, common, part and blank?
public String name() {
return name;
}
public void addValid() {
valid++;
}
public void addCommon() {
common++;
}
public void addPart() {
part++;
}
/**
* When it' s neither valid, commmon, nor part
*/
public void addBlank() {
blank++;
}
public void addTotal() {
total++;
}
public float getValid() {
return valid;
}
public float getCommon() {
return common;
}
public float getPart() {
return part;
}
public float getTotal() {
return total;
}
@Override
public String toString() {
return "SelectorResult[" +
"valid=" + valid +
", common=" + common +
", part=" + part +
", blank=" + blank +
"] with Spotter " + this.name;
}
public void printResult(SelectorResult baseResult) {
SelectorResult myMethod = this;
SelectorResult goldStandard = baseResult;
System.err.println("\n\n\n\nResult for Spotter '" + name() + "' compared with '" + baseResult.name() + "'");
System.err.println("\nSpotting took " + time + "ms, " +
String.format("%1.2f", time / (float) (baseResult.part + baseResult.valid + baseResult.common))
+ "ms per spot");
System.err.println(
" part:" + part + " (" + String.format("%1.2f", (((part/baseResult.getPart())) * 100)) + "%)" +
", common:" + common + " (" + String.format("%1.2f", (((common/baseResult.getCommon())) * 100)) + "%)" +
", valid:" + valid + " (" + String.format("%1.2f", (((valid/baseResult.getValid())) * 100)) + "%)" +
", blank:" + blank);
int spotted = part + common + valid + blank;
System.err.println(String.format("Precision: %s/%s = %1.2f",valid,myMethod.getTotal(), new Double(valid)/myMethod.getTotal()));
System.err.println(String.format("Recall: %s/%s = %1.2f", valid,goldStandard.getTotal(),new Double(valid)/goldStandard.getValid()));
System.err.println(String.format("Total: %s = Sum: %s ?", total, valid+common+part+blank));
}
public String getLatexResult(SelectorResult goldStandard) {
SelectorResult myMethod = this;
float timePerSpot = time / (float) (myMethod.getTotal());
double precision = (new Double(valid)/myMethod.getTotal()) * 100;
double recall = (new Double(valid)/goldStandard.getValid()) * 100;
double precisionNA = (common/goldStandard.getCommon()) * 100;
long spotted = (long) myMethod.getTotal();
long missed = (long) (goldStandard.getTotal() - myMethod.getValid());
StringBuffer b = new StringBuffer();
b.append("% spotter & P & R & $P_{NA}$ & N_{spotted} & N_{missed} & time per spot \\\\ \n");
b.append(String.format(" %s & %1.2f & %1.2f & %1.2f & %d & %d & %1.4f \\\\ \n", name(), precision, recall, precisionNA, spotted, missed, timePerSpot));
return b.toString();
}
/**
* Set the spotting time in ms.
*
* @param time time for the entire spotting process in ms
*/
public void setTime(long time) {
this.time = time;
}
}
}