/*
* EvaluationBasedOnDocs.java
*
* Yaoyong Li 22/03/2007
*
* $Id: EvaluationBasedOnDocs.java, v 1.0 2007-03-22 12:58:16 +0000 yaoyong $
*/
package gate.learning;
import gate.Annotation;
import gate.AnnotationSet;
import gate.Corpus;
import gate.Document;
import gate.Factory;
import gate.FeatureMap;
import gate.creole.ResourceInstantiationException;
import gate.util.AnnotationDiffer;
import gate.util.GateException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
/**
* Do evaluation by splitting the documents into training and testing datasets.
* Two methods of splitting are implemented, namely k-fold and hold-out test.
*/
public class EvaluationBasedOnDocs {
/** Corpus referring to the corpus used as data. */
Corpus corpusOn;
/** Number of documents in the corpus. */
int numDoc;
/**
* Showing if one document used for training or testing in one evaluation.
*/
boolean[] isUsedForTraining;
/** The sub-directory for storing the data file produced by ML api. */
File wdResults;
/** Name of the annotation set as input. */
String inputASName;
/** Storing the macro averaged overall F-measure results of the evaluation. */
public EvaluationMeasuresComputation macroMeasuresOfResults = new EvaluationMeasuresComputation();
/** Storing the macro averaged results of every label. */
HashMap labels2MMR = new HashMap();
/**
* Label to number of the runs having that label, used for macro-averaged for
* each label.
*/
HashMap labels2RunsNum = new HashMap();
/**
* Label to number of the instances with that label, averaged over the number
* of runs for that label.
*/
HashMap labels2InstNum = new HashMap();
/** Constructor. */
public EvaluationBasedOnDocs(Corpus corpus, File wdRes, String inputAsN) {
corpusOn = corpus;
numDoc = corpus.size();
isUsedForTraining = new boolean[numDoc];
wdResults = wdRes;
inputASName = inputAsN;
}
/**
* Main method for evaluation.
*
* @throws IOException
*/
public void evaluation(LearningEngineSettings learningSettings,
LightWeightLearningApi lightWeightApi) throws GateException, IOException {
// first obtain the feature vectors from documents
/*
* BufferedWriter outNLPFeatures=null; BufferedReader inNLPFeatures = null;
* BufferedWriter outFeatureVectors = null; boolean isTraining = true;
* outNLPFeatures = new BufferedWriter(new OutputStreamWriter(new
* FileOutputStream(new File(wdResults,
* ConstantParameters.FILENAMEOFNLPFeaturesData)), "UTF-8")); for(int i = 0;
* i < corpusOn.size(); ++i) { Document toProcess=
* (Document)corpusOn.get(i);
* lightWeightApi.annotations2NLPFeatures(toProcess, i, outNLPFeatures,
* isTraining, learningSettings); if(toProcess.getDataStore() != null &&
* corpusOn.getDataStore() != null) Factory.deleteResource(toProcess);
* //++numDoc; } outNLPFeatures.flush(); outNLPFeatures.close();
* lightWeightApi.finishFVs(wdResults, numDoc, isTraining,
* learningSettings); // Open the normal NLP feature file. inNLPFeatures =
* new BufferedReader(new InputStreamReader(new FileInputStream(new
* File(wdResults, ConstantParameters.FILENAMEOFNLPFeaturesData)),
* "UTF-8")); outFeatureVectors = new BufferedWriter(new
* OutputStreamWriter(new FileOutputStream( new
* File(wdResults,ConstantParameters.FILENAMEOFFeatureVectorTotalData)),
* "UTF-8")); lightWeightApi.nlpfeatures2FVs(wdResults, inNLPFeatures,
* outFeatureVectors, numDoc, isTraining, learningSettings);
* inNLPFeatures.close(); outFeatureVectors.flush();
* outFeatureVectors.close();
*/
// outFeatureVectors.close();
// k-fold
if(learningSettings.evaluationconfig.mode == EvaluationConfiguration.kfold)
kfoldEval(learningSettings, lightWeightApi);
// Hold-out testing
else if(learningSettings.evaluationconfig.mode == EvaluationConfiguration.split)
holdoutEval(learningSettings, lightWeightApi);
else throw new GateException("The evaluation configuration mode as "
+ learningSettings.evaluationconfig.mode + " is not implemented!");
StringBuffer logMes = new StringBuffer();
logMes.append("\n*** Averaged results for each label over "
+ learningSettings.evaluationconfig.kk + " runs as:\n");
logMes.append(printFmeasureForEachLabel(labels2InstNum, labels2MMR));
logMes.append("\nOverall results as:\n");
logMes.append(macroMeasuresOfResults.printResults());
LogService.logMessage(logMes.toString(), 1);
if(LogService.minVerbosityLevel > 0) System.out.println(logMes);
}
/** K-fold evaluation. */
public void kfoldEval(LearningEngineSettings learningSettings,
LightWeightLearningApi lightWeightApi) throws GateException {
int k = learningSettings.evaluationconfig.kk;
LogService.logMessage("K-fold evaluation: k=" + k, 1);
int lenPerFold = (new Double(Math.floor((double)numDoc / k))).intValue();
if(lenPerFold < 1) lenPerFold = 1;
int beginIndex, endIndex;
if(LogService.minVerbosityLevel > 0) {
System.out.println("Kfold k=" + new Integer(k) + ", numDoc="
+ new Integer(numDoc) + ", len=" + new Integer(lenPerFold) + ".");
}
LogService.logMessage("Kfold k=" + new Integer(k) + ", numDoc="
+ new Integer(numDoc) + ", len=" + new Integer(lenPerFold) + ".", 1);
for(int nr = 0; nr < k; ++nr) {
EvaluationMeasuresComputation measuresOfResults = new EvaluationMeasuresComputation();
// Label to measure of result of the label
HashMap labels2MR = new HashMap();
beginIndex = nr * lenPerFold;
endIndex = (nr + 1) * lenPerFold;
if(endIndex > numDoc) endIndex = numDoc;
if(beginIndex > endIndex) beginIndex = endIndex;
int i;
for(i = 0; i < beginIndex; ++i)
isUsedForTraining[i] = true;
for(i = beginIndex; i < endIndex; ++i)
isUsedForTraining[i] = false;
for(i = endIndex; i < numDoc; ++i)
isUsedForTraining[i] = true;
StringBuffer logMes = new StringBuffer();
int nr0 = nr + 1;
logMes.append("\n*** Fold " + nr0 + "\n");
logMes.append("Number of docs for training: "
+ (int)(numDoc - endIndex + beginIndex) + "\n");
int ik = 0;
for(i = 0; i < numDoc; ++i) {
if(isUsedForTraining[i]) {
++ik;
Document toProcess = (Document)corpusOn.get(i);
logMes
.append(ik + " " + toProcess.getName() + "\n");
if(toProcess.getDataStore() != null
&& corpusOn.getDataStore() != null)
Factory.deleteResource(toProcess);
}
}
logMes.append("Number of docs for application: "
+ (int)(endIndex - beginIndex) + "\n");
ik = 0;
for(i = 0; i < numDoc; ++i) {
if(!isUsedForTraining[i]) {
++ik;
Document toProcess = (Document)corpusOn.get(i);
logMes
.append(ik + " " + toProcess.getName() + "\n");
if(toProcess.getDataStore() != null
&& corpusOn.getDataStore() != null)
Factory.deleteResource(toProcess);
}
}
LogService.logMessage(logMes.toString(), 1);
if(LogService.minVerbosityLevel > 1) System.out.println(logMes);
// call the training or application
oneRun(learningSettings, lightWeightApi, isUsedForTraining,
measuresOfResults, labels2MR, labels2InstNum);
// Add to the macro averaged figures
add2MacroMeasure(measuresOfResults, labels2MR, macroMeasuresOfResults,
labels2MMR, labels2RunsNum);
}
macroMeasuresOfResults.macroAverage(k);
for(Object obj : labels2MMR.keySet()) {
int num = new Integer(labels2RunsNum.get(obj).toString()).intValue();
((EvaluationMeasuresComputation)labels2MMR.get(obj)).macroAverage(num);
num = (int)(new Float(labels2InstNum.get(obj).toString()).floatValue() / num);
labels2InstNum.put(obj, new Integer(num));
}
}
/** Hold-out testing. */
public void holdoutEval(LearningEngineSettings learningSettings,
LightWeightLearningApi lightWeightApi) throws GateException {
int k = learningSettings.evaluationconfig.kk;
LogService.logMessage("Hold-out test: runs=" + k
+ ", ratio of training docs is "
+ learningSettings.evaluationconfig.ratio, 1);
int trainingNum = (new Double(Math
.floor((numDoc * learningSettings.evaluationconfig.ratio))).intValue());
if(trainingNum > numDoc) trainingNum = numDoc;
LogService.logMessage("Split, k=" + new Integer(k) + ", trainingNum="
+ new Integer(trainingNum) + ".", 1);
if(LogService.minVerbosityLevel > 0) {
System.out.println("Hold-out test: runs=" + k
+ ", ratio of training docs is "
+ learningSettings.evaluationconfig.ratio);
System.out.println("Split, k=" + new Integer(k) + ", trainingNum="
+ new Integer(trainingNum) + ".");
}
int testNum = numDoc - trainingNum;
Random randGenerator = new Random(1000);
for(int nr = 0; nr < k; ++nr) {
EvaluationMeasuresComputation measuresOfResults = new EvaluationMeasuresComputation();
// Label to measure of result of the label
HashMap labels2MR = new HashMap();
// Select the training examples randomly from the data
int[] indexRand = new int[testNum];
for(int i = 0; i < testNum; ++i) {
int newNum = 0;
boolean isDuplicate = true;
int maxNumSel = 0;
while(isDuplicate && maxNumSel < 1000) {
newNum = randGenerator.nextInt(numDoc);
isDuplicate = false;
for(int j = 0; j < i; ++j)
if(indexRand[j] == newNum) {
isDuplicate = true;
break;
}
}
if(isDuplicate) {
// If cannot select a non-duplicate index in
// 1000 times, selected the one
boolean isOk = false;
for(int j = 0; j < numDoc; ++j) {
for(int j1 = 0; j1 < i; ++j1)
if(indexRand[j1] != j) {
newNum = j;
isOk = true;
break;
}
if(isOk) break;
}
}
if(LogService.minVerbosityLevel > 1) {
System.out.println("i=" + new Integer(i) + ", newNum="
+ new Integer(newNum));
}
indexRand[i] = newNum;
}
for(int i = 0; i < numDoc; ++i)
isUsedForTraining[i] = true;
for(int i = 0; i < testNum; ++i)
isUsedForTraining[indexRand[i]] = false;
StringBuffer logMes = new StringBuffer();
int nr0 = nr + 1;
logMes.append("\n*** Run " + nr0 + "\n");
logMes.append("Number of docs for training: " + (int)(numDoc - testNum)
+ "\n");
int ik = 0;
for(int i = 0; i < numDoc; ++i) {
if(isUsedForTraining[i]) {
++ik;
Document toProcess = (Document)corpusOn.get(i);
logMes
.append(ik + " " + toProcess.getName() + "\n");
if(toProcess.getDataStore() != null
&& corpusOn.getDataStore() != null)
Factory.deleteResource(toProcess);
}
}
logMes.append("Number of docs for application: " + testNum + "\n");
ik = 0;
for(int i = 0; i < numDoc; ++i) {
if(!isUsedForTraining[i]) {
++ik;
Document toProcess = (Document)corpusOn.get(i);
logMes
.append(ik + " " + toProcess.getName() + "\n");
if(toProcess.getDataStore() != null
&& corpusOn.getDataStore() != null)
Factory.deleteResource(toProcess);
}
}
LogService.logMessage(logMes.toString(), 1);
if(LogService.minVerbosityLevel > 1) System.out.println(logMes);
// One run, call the training and application and do evaluation
oneRun(learningSettings, lightWeightApi, isUsedForTraining,
measuresOfResults, labels2MR, labels2InstNum);
// Add to the macro averaged figures
add2MacroMeasure(measuresOfResults, labels2MR, macroMeasuresOfResults,
labels2MMR, labels2RunsNum);
}
macroMeasuresOfResults.macroAverage(k);
for(Object obj : labels2MMR.keySet()) {
int num = new Integer(labels2RunsNum.get(obj).toString()).intValue();
((EvaluationMeasuresComputation)labels2MMR.get(obj)).macroAverage(num);
// Averaged the number of instances for all the runs
num = (int)(new Float(labels2InstNum.get(obj).toString()).floatValue() / num);
labels2InstNum.put(obj, new Integer(num));
}
}
/**
* One run of the evaluation: training, testing and measuring results.
*
* @throws
* @throws UnsupportedEncodingException
*/
private void oneRun(LearningEngineSettings learningSettings,
LightWeightLearningApi lightWeightApi, boolean isUsedForTraining[],
EvaluationMeasuresComputation measuresOfResults, HashMap labels2MR,
HashMap labels2InstNum) throws GateException {
// first learning using the document for training
// empty the data file
emptyDatafile(wdResults, true);
lightWeightApi.labelsAndId.clearAllData();
lightWeightApi.featuresList.clearAllData();
boolean isTraining = true;
int numDoc = 0;
BufferedWriter outNLPFeatures = null;
BufferedReader inNLPFeatures = null;
BufferedWriter outFeatureVectors = null;
try {
outNLPFeatures = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(new File(wdResults,
ConstantParameters.FILENAMEOFNLPFeaturesData)), "UTF-8"));
for(int i = 0; i < corpusOn.size(); ++i)
if(isUsedForTraining[i]) {
Document toProcess = (Document)corpusOn.get(i);
lightWeightApi.annotations2NLPFeatures(toProcess, numDoc,
outNLPFeatures, isTraining, learningSettings);
if(toProcess.getDataStore() != null
&& corpusOn.getDataStore() != null)
Factory.deleteResource(toProcess);
++numDoc;
}
outNLPFeatures.flush();
outNLPFeatures.close();
lightWeightApi.finishFVs(wdResults, numDoc, isTraining, learningSettings);
// Open the normal NLP feature file.
inNLPFeatures = new BufferedReader(new InputStreamReader(
new FileInputStream(new File(wdResults,
ConstantParameters.FILENAMEOFNLPFeaturesData)), "UTF-8"));
outFeatureVectors = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(new File(wdResults,
ConstantParameters.FILENAMEOFFeatureVectorData)), "UTF-8"));
lightWeightApi.nlpfeatures2FVs(wdResults, inNLPFeatures,
outFeatureVectors, numDoc, isTraining, learningSettings);
inNLPFeatures.close();
outFeatureVectors.flush();
outFeatureVectors.close();
// outFeatureVectors.close();
// read the fv data from total file and write them into fv files for
// training and application, respectively
/*
* BufferedReader inFVs = new BufferedReader(new InputStreamReader(new
* FileInputStream(new File(wdResults,
* ConstantParameters.FILENAMEOFFeatureVectorTotalData)), "UTF-8"));
* BufferedWriter outFVs = new BufferedWriter(new OutputStreamWriter(new
* FileOutputStream( new
* File(wdResults,ConstantParameters.FILENAMEOFFeatureVectorData)),
* "UTF-8")); BufferedWriter outFVsApp = new BufferedWriter(new
* OutputStreamWriter(new FileOutputStream( new
* File(wdResults,ConstantParameters.FILENAMEOFFeatureVectorDataApp)),
* "UTF-8")); for(int i = 0; i < corpusOn.size(); ++i) { String str =
* inFVs.readLine(); int numLines =
* Integer.parseInt(str.substring(str.indexOf(ConstantParameters.ITEMSEPARATOR)+1,
* str.lastIndexOf(ConstantParameters.ITEMSEPARATOR)));
* if(isUsedForTraining[i]) { outFVs.append(str); outFVs.newLine();
* for(int j=0; j<numLines; ++j) { outFVs.append(inFVs.readLine());
* outFVs.newLine(); } ++numDoc; } else { outFVsApp.append(str);
* outFVsApp.newLine(); for(int j=0; j<numLines; ++j) {
* outFVsApp.append(inFVs.readLine()); outFVsApp.newLine(); } } }
* inFVs.close(); outFVs.flush(); outFVs.close(); outFVsApp.flush();
* outFVsApp.close();
*/
// if fitering the training data
if(learningSettings.fiteringTrainingData
&& learningSettings.filteringRatio > 0.0)
lightWeightApi.FilteringNegativeInstsInJava(numDoc, learningSettings);
// lightWeightApi.trainDirect();
lightWeightApi.trainingJava(numDoc, learningSettings);
// then application to the test set
// First we empty the NLP feature file and feature vector file; but not
// the list files.
emptyDatafile(wdResults, false);
// We have to use two class types for the evaluation purpose
String classTypeOriginal = null;
String classTypeTest = null;
String classFeature = null;
classTypeOriginal = learningSettings.datasetDefinition
.getClassAttribute().getType();
classTypeTest = classTypeOriginal.concat("Test");
classFeature = learningSettings.datasetDefinition.getClassAttribute()
.getFeature();
learningSettings.datasetDefinition.getClassAttribute().setType(
classTypeTest);
if(LogService.minVerbosityLevel > 1)
System.out.println("classType=" + classTypeOriginal + ", testType="
+ classTypeTest + ".");
isTraining = false;
// numDoc = isUsedForTraining.length - numDoc;
numDoc = 0;
outNLPFeatures = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(new File(wdResults,
ConstantParameters.FILENAMEOFNLPFeaturesData)), "UTF-8"));
for(int i = 0; i < corpusOn.size(); ++i)
if(!isUsedForTraining[i]) {
Document toProcess = (Document)corpusOn.get(i);
lightWeightApi.annotations2NLPFeatures(toProcess,
numDoc, outNLPFeatures, isTraining, learningSettings);
++numDoc;
if(toProcess.getDataStore() != null
&& corpusOn.getDataStore() != null) {
corpusOn.getDataStore().sync(corpusOn);
Factory.deleteResource(toProcess);
}
}
outNLPFeatures.flush();
outNLPFeatures.close();
lightWeightApi.finishFVs(wdResults, numDoc, isTraining, learningSettings);
inNLPFeatures = new BufferedReader(new InputStreamReader(
new FileInputStream(new File(wdResults,
ConstantParameters.FILENAMEOFNLPFeaturesData)), "UTF-8"));
outFeatureVectors = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(new File(wdResults,
ConstantParameters.FILENAMEOFFeatureVectorDataApp)), "UTF-8"));
lightWeightApi.nlpfeatures2FVs(wdResults, inNLPFeatures,
outFeatureVectors, numDoc, isTraining, learningSettings);
inNLPFeatures.close();
outFeatureVectors.flush();
outFeatureVectors.close();
// lightWeightApi.finishDocAnnotation();
Corpus corpusTest;
corpusTest = Factory.newCorpus("testCorpus");
if(corpusOn.getDataStore() != null) {
Corpus corpusTestTemp = (Corpus)corpusOn.getDataStore().adopt(corpusTest, null);
Factory.deleteResource(corpusTest);
corpusTest = corpusTestTemp;
corpusTest.getDataStore().sync(corpusTest);
}
numDoc = 0;
for(int i = 0; i < corpusOn.size(); ++i)
if(!isUsedForTraining[i]) {
Document d = (Document)corpusOn.get(i);
corpusTest.add(d);
if(corpusTest.getDataStore() != null) {
corpusTest.getDataStore().sync(corpusTest);
Factory.deleteResource(d);
}
++numDoc;
}
String fvFileName = wdResults.toString() + File.separator
+ ConstantParameters.FILENAMEOFFeatureVectorDataApp;
lightWeightApi.applyModelInJava(corpusTest, 0, corpusTest.size(),
classTypeTest, learningSettings, fvFileName);
//unload the documents in the test corpus from memory
/*for(int i=0; i<corpusTest.size(); ++i) {
Document toProcess = (Document)corpusOn.get(i);
if(corpusOn.getDataStore() != null) {
corpusOn.getDataStore().sync(corpusOn);
Factory.deleteResource(toProcess);
}
}*/
corpusTest.clear();
Factory.deleteResource(corpusTest);
if(corpusTest.getDataStore() != null) {
corpusTest.getDataStore().delete(corpusTest.getClass().getName(), corpusTest.getLRPersistenceId());
}
// Do the evaluation on test using the AnnotationDiff
// First get all the labels in the training data,
// so that we can do evaluation on each single label
// as well as on all labels
HashMap uniqueLabels = new HashMap();
for(int i = 0; i < corpusOn.size(); ++i)
if(isUsedForTraining[i]) {
Document toProcess = (Document)corpusOn.get(i);
AnnotationSet keyAnns = getInputAS(toProcess).get(classTypeOriginal);
for(Object obj : keyAnns) {
if(((Annotation)obj).getFeatures().get(classFeature) != null) {
String label = ((Annotation)obj).getFeatures().get(classFeature)
.toString();
if(uniqueLabels.containsKey(label))
uniqueLabels.put(label, new Integer(new Integer(uniqueLabels
.get(label).toString()).intValue() + 1));
else uniqueLabels.put(label, "1");
}
}
if(toProcess.getDataStore() != null
&& corpusOn.getDataStore() != null) {
corpusOn.getDataStore().sync(corpusOn);
Factory.deleteResource(toProcess);
}
}
// Then create one evaluationMeasure object for each label
for(Object obj : uniqueLabels.keySet()) {
EvaluationMeasuresComputation emc = new EvaluationMeasuresComputation();
labels2MR.put(obj, emc);
}
// Copy the number of instances for each label into the macro one
for(Object obj : uniqueLabels.keySet()) {
if(labels2InstNum.containsKey(obj)) {
int num = new Integer(uniqueLabels.get(obj).toString()).intValue();
labels2InstNum.put(obj, new Integer(new Integer(labels2InstNum.get(
obj).toString()).intValue()
+ num));
} else labels2InstNum.put(obj, uniqueLabels.get(obj));
}
// Do the evaluation on the test set
if(learningSettings.datasetDefinition.dataType == DataSetDefinition.RelationData) {
// For relation type, we cannot use the evaluation method AnnDiff
// of Gate
AttributeRelation relAttr = (AttributeRelation)learningSettings.datasetDefinition
.getClassAttribute();
String arg1F = relAttr.getArg1();
String arg2F = relAttr.getArg2();
for(int i = 0; i < corpusOn.size(); ++i) {
if(!isUsedForTraining[i]) {
Document toProcess = (Document)corpusOn.get(i);
evaluateAnnotationsRel(toProcess,
classTypeOriginal, classTypeTest, classFeature, arg1F, arg2F,
uniqueLabels.keySet(), labels2MR);
if(toProcess.getDataStore() != null
&& corpusOn.getDataStore() != null) {
corpusOn.getDataStore().sync(corpusOn);
Factory.deleteResource(toProcess);
}
}
}
} else {
/*
* for(int i=0; i<corpusOn.size(); ++i) { if(! isUsedForTraining[i]) {
* evaluateAnnotations((Document)corpusOn.get(i), classTypeOriginal,
* classTypeTest, classFeature, uniqueLabels.keySet(), labels2MR); } }
*/
// evaluation on each label using the AnnDiff method of Gate
for(int i = 0; i < corpusOn.size(); ++i)
if(!isUsedForTraining[i]) {
Document toProcess = (Document)corpusOn.get(i);
evaluateAnnDiff(toProcess, classTypeOriginal,
classTypeTest, classFeature, uniqueLabels.keySet(), labels2MR);
if(toProcess.getDataStore() != null
&& corpusOn.getDataStore() != null) {
corpusOn.getDataStore().sync(corpusOn);
Factory.deleteResource(toProcess);
}
}
}
// Pool the results of all labels together
for(Object obj : uniqueLabels.keySet())
measuresOfResults
.add((EvaluationMeasuresComputation)labels2MR.get(obj));
measuresOfResults.computeFmeasure();
measuresOfResults.computeFmeasureLenient();
for(Object obj : uniqueLabels.keySet()) {
EvaluationMeasuresComputation emc = (EvaluationMeasuresComputation)labels2MR
.get(obj);
emc.computeFmeasure();
emc.computeFmeasureLenient();
}
StringBuffer logMes = new StringBuffer();
logMes.append("Results of this run:\n\n");
logMes.append(printFmeasureForEachLabel(uniqueLabels, labels2MR));
logMes.append("\nOverall results(micro-averaged over all labels):\n");
logMes.append(measuresOfResults.printResults());
if(LogService.minVerbosityLevel > 1) {
System.out.println(logMes);
}
LogService.logMessage(logMes.toString(), 1);
// finally, change the class type back for training,
// and remove the test annotations
learningSettings.datasetDefinition.getClassAttribute().setType(
classTypeOriginal);
for(int i = 0; i < corpusOn.size(); ++i) {
if(!isUsedForTraining[i]) {
Document toProcess = (Document)corpusOn.get(i);
AnnotationSet annsInput = getInputAS(toProcess);
AnnotationSet anns = annsInput.get(classTypeTest);
Iterator iter = anns.iterator();
while(iter.hasNext())
annsInput.remove((Annotation)iter.next());
if(toProcess.getDataStore() != null
&& corpusOn.getDataStore() != null) {
corpusOn.getDataStore().sync(corpusOn);
Factory.deleteResource(toProcess);
}
}
}
} catch(ResourceInstantiationException e) {
e.printStackTrace();
} catch(UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch(FileNotFoundException e1) {
e1.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
}
/** Empty the label list and feature list. */
public static void emptyDatafile(File wdResults, boolean isRemoveList) {
if(isRemoveList) {
(new File(wdResults, ConstantParameters.FILENAMEOFNLPFeatureList))
.delete();
(new File(wdResults, ConstantParameters.FILENAMEOFLabelList)).delete();
(new File(wdResults, ConstantParameters.FILENAMEOFChunkLenStats))
.delete();
(new File(wdResults, ConstantParameters.FILENAMEOFLabelsInData)).delete();
try {
(new File(wdResults, ConstantParameters.FILENAMEOFNLPFeatureList))
.createNewFile();
} catch(IOException e) {
e.printStackTrace();
}
}
(new File(wdResults, ConstantParameters.FILENAMEOFNLPFeaturesData))
.delete();
(new File(wdResults, ConstantParameters.FILENAMEOFFeatureVectorData))
.delete();
(new File(wdResults, ConstantParameters.FILENAMEOFNLPDataLabel)).delete();
System.gc(); // to make effort to delete the files.
}
/** Add the F-measure of each label to the overal F-measure */
public void add2MacroMeasure(EvaluationMeasuresComputation measuresOfResults,
HashMap labels2MR, EvaluationMeasuresComputation macroMeasuresOfResults,
HashMap labels2MMR, HashMap labels2RunsNum) {
macroMeasuresOfResults.add(measuresOfResults);
// for each label
for(Object obj : labels2MR.keySet()) {
String label = obj.toString();
if(labels2MMR.containsKey(label)) {// the label is in the macro
// Array already
((EvaluationMeasuresComputation)labels2MMR.get(label))
.add(((EvaluationMeasuresComputation)(labels2MR.get(label))));
labels2RunsNum.put(label, new Integer((new Integer(labels2RunsNum.get(
label).toString()).intValue() + 1)));
} else {
// labels2MMR.put(label, new EvaluationMeasuresComputation());
EvaluationMeasuresComputation emc = new EvaluationMeasuresComputation();
emc.add((EvaluationMeasuresComputation)(labels2MR.get(label)));
labels2MMR.put(label, emc);
labels2RunsNum.put(label, "1");
}
}
}
/** Print the F-measure results for each label. */
public String printFmeasureForEachLabel(HashMap uniqueLabels,
HashMap labels2MR) {
StringBuffer logMes = new StringBuffer();
logMes.append("\nResults of single label:\n");
// LogService.logMessage("\nResults of single label", 1);
List labels = new ArrayList(uniqueLabels.keySet());
Collections.sort(labels);
for(int i = 0; i < labels.size(); ++i) {
String labelName = labels.get(i).toString();
logMes.append(i + " LabelName=" + labelName + ", number of instances="
+ new Integer(uniqueLabels.get(labelName).toString()) + "\n");
logMes.append(((EvaluationMeasuresComputation)labels2MR.get(labelName))
.printResults());
// ((EvaluationMeasuresComputation)labels2MR.get(labelName))
// .printResults(logFileIn);
}
return logMes.toString();
}
/** Evaluate the test document by using the AnnotationDiff class. */
public void evaluateAnnDiff(Document doc, String classTypeOriginal,
String classTypeTest, String classFeat, Set labelSet, HashMap labels2MR) {
// for each label
AnnotationSet annsOriginal = getInputAS(doc).get(classTypeOriginal);
AnnotationSet annsTest = getInputAS(doc).get(classTypeTest);
HashSet annsKey = new HashSet();
HashSet annsRes = new HashSet();
HashSet signSet = new HashSet();
signSet.add(classFeat);
for(Object obj : labelSet) {
String label = obj.toString();
annsKey.clear();
annsRes.clear();
for(Object objAnn : annsOriginal)
if(((FeatureMap)((Annotation)objAnn).getFeatures()).get(classFeat) != null)
if(((FeatureMap)((Annotation)objAnn).getFeatures()).get(classFeat)
.toString().equals(label)) annsKey.add(objAnn);
for(Object objAnn : annsTest)
if(((FeatureMap)((Annotation)objAnn).getFeatures()).get(classFeat) != null)
if(((FeatureMap)((Annotation)objAnn).getFeatures()).get(classFeat)
.toString().equals(label)) annsRes.add(objAnn);
AnnotationDiffer annDiff = new AnnotationDiffer();
annDiff.setSignificantFeaturesSet(signSet);
annDiff.calculateDiff(annsKey, annsRes);
EvaluationMeasuresComputation emc = (EvaluationMeasuresComputation)labels2MR
.get(label);
emc.correct += annDiff.getCorrectMatches();
emc.partialCor += annDiff.getPartiallyCorrectMatches();
emc.missing += annDiff.getMissing();
emc.spurious += annDiff.getSpurious();
}
}
/**
* Evaluate the test document by comparing the annotations with the golden
* standard
*/
public void evaluateAnnotations(Document doc, String classTypeOriginal,
String classTypeTest, String classFeat, Set labelSet, HashMap labels2MR) {
AnnotationSet annsOriginal = getInputAS(doc).get(classTypeOriginal);
AnnotationSet annsTest = getInputAS(doc).get(classTypeTest);
HashSet annsKey = new HashSet();
HashSet annsRes = new HashSet();
// For each label
for(Object obj : labelSet) {
String label = obj.toString();
annsKey.clear();
annsRes.clear();
for(Object objAnn : annsOriginal) {
Object label0 = ((Annotation)objAnn).getFeatures().get(classFeat);
if(label0 != null && label0.equals(label)) annsKey.add(objAnn);
}
for(Object objAnn : annsTest) {
Object label0 = ((Annotation)objAnn).getFeatures().get(classFeat);
if(label0 != null && label0.equals(label)) annsRes.add(objAnn);
}
EvaluationMeasuresComputation measuresOfResults = (EvaluationMeasuresComputation)labels2MR
.get(label);
for(Object annOrig : annsKey) {
boolean isMatch = false;
for(Object annTest : annsRes)
if(((Annotation)annTest).coextensive(((Annotation)annOrig))) {
measuresOfResults.correct++;
isMatch = true;
break;
}
if(!isMatch) measuresOfResults.missing++;
}
for(Object annTest : annsRes) {
boolean isMatch = false;
for(Object annOrig : annsKey)
if(((Annotation)annTest).coextensive(((Annotation)annOrig))) {
isMatch = true;
break;
}
if(!isMatch) measuresOfResults.spurious++;
}
}
}
/**
* Evaluate the test document by comparing the annotations with the golden
* standard, for Relation learning
*/
public void evaluateAnnotationsRel(Document doc, String classTypeOriginal,
String classTypeTest, String classFeat, String arg1F, String arg2F,
Set labelSet, HashMap labels2MR) {
AnnotationSet annsOriginal = getInputAS(doc).get(classTypeOriginal);
AnnotationSet annsTest = getInputAS(doc).get(classTypeTest);
HashSet annsKey = new HashSet();
HashSet annsRes = new HashSet();
// For each label
for(Object obj : labelSet) {
String label = obj.toString();
annsKey.clear();
annsRes.clear();
for(Object objAnn : annsOriginal) {
Object label0 = ((Annotation)objAnn).getFeatures().get(classFeat);
if(label0 != null && label0.equals(label)) annsKey.add(objAnn);
}
for(Object objAnn : annsTest) {
Object label0 = ((Annotation)objAnn).getFeatures().get(classFeat);
if(label0 != null && label0.equals(label)) annsRes.add(objAnn);
}
EvaluationMeasuresComputation measuresOfResults = (EvaluationMeasuresComputation)labels2MR
.get(label);
for(Object annOrig : annsKey) {
Object arg1VO = ((Annotation)annOrig).getFeatures().get(arg1F);
Object arg2VO = ((Annotation)annOrig).getFeatures().get(arg2F);
boolean isMatch = false;
for(Object annTest : annsRes) {
FeatureMap feats = ((Annotation)annTest).getFeatures();
if(arg1VO.equals(feats.get(arg1F)) && arg2VO.equals(feats.get(arg2F))) {
measuresOfResults.correct++;
isMatch = true;
break;
}
}
if(!isMatch) measuresOfResults.missing++;
}
for(Object annTest : annsRes) {
Object arg1VO = ((Annotation)annTest).getFeatures().get(arg1F);
Object arg2VO = ((Annotation)annTest).getFeatures().get(arg2F);
boolean isMatch = false;
for(Object annOrig : annsKey) {
FeatureMap feats = ((Annotation)annOrig).getFeatures();
if(arg1VO.equals(feats.get(arg1F)) && arg2VO.equals(feats.get(arg2F))) {
isMatch = true;
break;
}
}
if(!isMatch) measuresOfResults.spurious++;
}
}
}
private AnnotationSet getInputAS(Document doc) {
if(inputASName == null || inputASName.trim().length() == 0) {
return doc.getAnnotations();
} else {
return doc.getAnnotations(inputASName);
}
}
}