Commit 846d3a60 authored by Bruno López Trigo's avatar Bruno López Trigo

Solventado problema con SimpleNLG e inicio de explicación local

parent 5e9f723a
......@@ -66,17 +66,6 @@
<scope>system</scope>
<systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/cycles.jar</systemPath>
</dependency>
<!-- SimpleNLG -->
<dependency>
<groupId>uk.ac.abdn</groupId>
<artifactId>SimpleNLG</artifactId>
<version>4.4.8</version>
</dependency>
<dependency>
<groupId>com.github.citiususc</groupId>
<artifactId>SimpleNLG-ES</artifactId>
<version>v1.0</version>
</dependency>
<dependency>
<groupId>com.github.citiususc</groupId>
<artifactId>SimpleNLG-GL</artifactId>
......
......@@ -120,9 +120,9 @@ public class BuilderManagerImpl implements BuilderManager {
((NumericAttribute)config.getAttributes().get(i)).setInterval(new Interval(minMax[0], minMax[1]));
config.getAttributes().get(i).getProperties().add(new NumericProperty("Low", new Interval(minMax[0], minMax[0] + distance)));
config.getAttributes().get(i).getProperties().add(new NumericProperty("Medium", new Interval(minMax[0] + distance, minMax[0] + 2 * distance)));
config.getAttributes().get(i).getProperties().add(new NumericProperty("High", new Interval(minMax[0] + 2 * distance, minMax[1])));
config.getAttributes().get(i).getProperties().add(new NumericProperty("Low", new Interval(minMax[0], minMax[0] + distance), 0));
config.getAttributes().get(i).getProperties().add(new NumericProperty("Medium", new Interval(minMax[0] + distance, minMax[0] + 2 * distance), 1));
config.getAttributes().get(i).getProperties().add(new NumericProperty("High", new Interval(minMax[0] + 2 * distance, minMax[1]), 2));
} else{
config.getAttributes().add(new CategoricAttribute(instancesLRN.attribute(i).name(), instancesLRN.attribute(i).name()));
......
......@@ -2,11 +2,17 @@ package brunolopez.expliclas.classifiers;
import brunolopez.expliclas.exceptions.ConflictEx;
import brunolopez.expliclas.exceptions.FormatEx;
import brunolopez.expliclas.exceptions.NotAllowedEx;
import brunolopez.expliclas.exceptions.NotFoundEx;
import brunolopez.expliclas.models.Attribute;
import brunolopez.expliclas.models.Classification;
import brunolopez.expliclas.models.Consequent;
import brunolopez.expliclas.models.DatasetConfig;
import brunolopez.expliclas.models.Instance;
import brunolopez.expliclas.models.Matrix;
import brunolopez.expliclas.models.NumericAttribute;
import brunolopez.expliclas.models.NumericProperty;
import brunolopez.expliclas.models.Property;
import brunolopez.expliclas.models.VisualNode;
import java.io.IOException;
import java.util.ArrayList;
......@@ -14,7 +20,12 @@ import java.util.ArrayList;
public interface ClassifierManager {
public DatasetConfig getConfig(String token, String dataset, String lang) throws NotFoundEx, IOException;
public DatasetConfig updateConfig(String token, String dataset, DatasetConfig config, String lang) throws NotFoundEx, FormatEx, IOException;
public Attribute getAttributeConfig(String token, String dataset, String attribute, String lang) throws NotFoundEx, IOException;
public Consequent getConsequentConfig(String token, String dataset, String consequent, String lang) throws NotFoundEx, IOException;
public Property getPropertyConfig(String token, String dataset, String attribute, int property, String lang) throws NotFoundEx, IOException;
public Property removePropertyConfig(String token, String dataset, String attribute, int property, String lang) throws NotFoundEx, IOException, NotAllowedEx, FormatEx;
public NumericAttribute updateAttributeConfig(String token, String dataset, String attribute, NumericAttribute attributeConfig, String lang) throws NotFoundEx, IOException, FormatEx;
public NumericAttribute updateAttributeConfig(String token, String dataset, String attribute, NumericProperty property, String lang) throws NotFoundEx, IOException, FormatEx;
public VisualNode buildTree(String token, String dataset, String algorithm) throws NotFoundEx, FormatEx, ConflictEx, IOException;
public VisualNode getTree(String token, String dataset, String algorithm, String lang) throws NotFoundEx, IOException;
public Classification classify(String token, String dataset, String algorithm, String lang, Instance instance) throws NotFoundEx, FormatEx, IOException;
......
......@@ -109,7 +109,7 @@ public class TreeInterpreter {
} else if (path.get(path.size() - 1) instanceof CategoricNode) {
att = ((CategoricNode) path.get(path.size() - 1)).getAttribute();
path.add(((CategoricNode) path.get(path.size() - 1)).getChild(instance.getCategoricValue(att.getId())));
classification.addAntecedent(new Antecedent(att.getId() + " is " + instance.getCategoricValue(att.getId()), att.getId()));
classification.addAntecedent(new Antecedent(att.getId() + " is " + instance.getCategoricValue(att.getId())));
}
if (path.get(path.size() - 1) instanceof ConsequentNode) {
classification.setConsequent(((ConsequentNode) path.get(path.size() - 1)).getConsequent());
......@@ -245,7 +245,7 @@ public class TreeInterpreter {
} else if (path.get(path.size() - 1) instanceof CategoricNode) {
att = ((CategoricNode) path.get(path.size() - 1)).getAttribute();
path.add(((CategoricNode) path.get(path.size() - 1)).getChild(alternatives.get(0).getCategoricValue(att.getId())));
classification.addAntecedent(new Antecedent(att.getId() + " is " + alternatives.get(0).getCategoricValue(att.getId()), att.getId()));
classification.addAntecedent(new Antecedent(att.getId() + " is " + alternatives.get(0).getCategoricValue(att.getId())));
}
if (path.get(path.size() - 1) instanceof ConsequentNode) {
classification.setConsequent(((ConsequentNode) path.get(path.size() - 1)).getConsequent());
......@@ -265,16 +265,18 @@ public class TreeInterpreter {
return classifications;
}
private String getLabelInterval(Interval interval, NumericAttribute att, DatasetConfig config) {
private int getLabelInterval(Interval interval, NumericAttribute att, DatasetConfig config) {
String label = "";
int label = 0;
double best = 0, actual;
Property p;
for (Property prop : att.getProperties()) {
actual = ((NumericProperty) prop).getInterval().coincidencePercentage(interval);
if (actual > best) {
best = actual;
label = ((NumericAttribute) config.getAttributeById(att.getId())).getPropertyByInterval(((NumericProperty) prop).getInterval()).getName();
p = ((NumericAttribute) config.getAttributeById(att.getId())).getPropertyByInterval(((NumericProperty) prop).getInterval());
label = ((NumericProperty) p).getId();
}
}
......
package brunolopez.expliclas.exceptions;
public class NotAllowedEx extends Exception {
public NotAllowedEx(String message) {
super(message);
}
}
......@@ -2,7 +2,6 @@ package brunolopez.expliclas.explainer;
import java.util.ArrayList;
import simplenlg.features.Feature;
import simplenlg.features.NumberAgreement;
import simplenlg.framework.CoordinatedPhraseElement;
import simplenlg.framework.NLGElement;
import simplenlg.framework.NLGFactory;
......@@ -15,15 +14,16 @@ public abstract class ClauseGenerator {
private Lexicon lexicon;
private NLGFactory nlgFactory;
public ClauseGenerator(Lexicon lexicon) {
this.nlgFactory = new NLGFactory(lexicon);
this.lexicon = lexicon;
this.nlgFactory = new NLGFactory(lexicon);
}
public Lexicon getLexicon() {
return lexicon;
}
public NLGFactory getNlgFactory() {
return nlgFactory;
}
......@@ -70,6 +70,52 @@ public abstract class ClauseGenerator {
}
SPhraseSpec generateClauseSubjectElement(String determiner, NLGElement subject, String verb, boolean pluralVerb, String object, boolean pluralObject) {
SPhraseSpec phrase = this.getNlgFactory().createClause();
VPPhraseSpec verbPhrase = this.getNlgFactory().createVerbPhrase(verb);
verbPhrase.setPlural(pluralVerb);
NPPhraseSpec subjectPhrase = this.getNlgFactory().createNounPhrase(subject);
subjectPhrase.setDeterminer(determiner);
NPPhraseSpec objectPhrase = this.getNlgFactory().createNounPhrase(object);
objectPhrase.setPlural(pluralObject);
if(subject!=null){
phrase.setSubject(subjectPhrase);
phrase.setVerbPhrase(verbPhrase);
phrase.setObject(objectPhrase);
}
else{
phrase = this.getNlgFactory().createClause(null, verbPhrase, objectPhrase);
}
return phrase;
}
public SPhraseSpec generateClauseSubjectElement(NLGElement subject, String verb, boolean plural, String object) {
SPhraseSpec phrase = this.getNlgFactory().createClause();
VPPhraseSpec verbPhrase = this.getNlgFactory().createVerbPhrase(verb);
verbPhrase.setPlural(plural);
NPPhraseSpec subjectPhrase = this.getNlgFactory().createNounPhrase(subject);
NPPhraseSpec objectPhrase = this.getNlgFactory().createNounPhrase(object);
if(subject!=null){
phrase.setSubject(subjectPhrase);
phrase.setVerbPhrase(verbPhrase);
phrase.setObject(objectPhrase);
}
else{
phrase = this.getNlgFactory().createClause(null, verbPhrase, objectPhrase);
}
return phrase;
}
public SPhraseSpec generateClause(String subject, String verb, boolean plural, String object) {
SPhraseSpec phrase = this.getNlgFactory().createClause();
VPPhraseSpec verbPhrase = this.getNlgFactory().createVerbPhrase(verb);
......@@ -91,7 +137,80 @@ public abstract class ClauseGenerator {
return phrase;
}
public SPhraseSpec generateClause(String determiner, String subject, String verb, boolean plural, String object) {
SPhraseSpec phrase = this.getNlgFactory().createClause();
VPPhraseSpec verbPhrase = this.getNlgFactory().createVerbPhrase(verb);
verbPhrase.setPlural(plural);
NPPhraseSpec subjectPhrase = this.getNlgFactory().createNounPhrase(subject);
subjectPhrase.setDeterminer(determiner);
NPPhraseSpec objectPhrase = this.getNlgFactory().createNounPhrase(object);
if(subject!=null){
phrase.setSubject(subjectPhrase);
phrase.setVerbPhrase(verbPhrase);
phrase.setObject(objectPhrase);
}
else{
phrase = this.getNlgFactory().createClause(null, verbPhrase, objectPhrase);
}
return phrase;
}
public SPhraseSpec generateClauseObjectElement(String subjectModifier, String subject, String verb, boolean plural, String objectModifier, NLGElement object) {
SPhraseSpec phrase = this.getNlgFactory().createClause();
VPPhraseSpec verbPhrase = this.getNlgFactory().createVerbPhrase(verb);
verbPhrase.setPlural(plural);
NPPhraseSpec subjectPhrase = this.getNlgFactory().createNounPhrase(subject);
subjectPhrase.setPreModifier(subjectModifier);
NPPhraseSpec objectPhrase = this.getNlgFactory().createNounPhrase(object);
objectPhrase.setPreModifier(objectModifier);
if(subject!=null){
phrase.setSubject(subjectPhrase);
phrase.setVerbPhrase(verbPhrase);
phrase.setObject(objectPhrase);
}
else{
verbPhrase.addPreModifier(subjectModifier);
phrase = this.getNlgFactory().createClause(null, verbPhrase, objectPhrase);
}
return phrase;
}
public SPhraseSpec generateClauseObject(String subjectModifier, String subject, String verb, boolean plural, String objectModifier, String object) {
SPhraseSpec phrase = this.getNlgFactory().createClause();
VPPhraseSpec verbPhrase = this.getNlgFactory().createVerbPhrase(verb);
verbPhrase.setPlural(plural);
NPPhraseSpec subjectPhrase = this.getNlgFactory().createNounPhrase(subject);
subjectPhrase.setPreModifier(subjectModifier);
NPPhraseSpec objectPhrase = this.getNlgFactory().createNounPhrase(object);
objectPhrase.setPreModifier(objectModifier);
if(subject!=null){
phrase.setSubject(subjectPhrase);
phrase.setVerbPhrase(verbPhrase);
phrase.setObject(objectPhrase);
}
else{
verbPhrase.addPreModifier(subjectModifier);
phrase = this.getNlgFactory().createClause(null, verbPhrase, objectPhrase);
}
return phrase;
}
public SPhraseSpec generateClausePreModifier(String subject, boolean plural, String subjectModifier, String verb, String object) {
SPhraseSpec phrase = this.getNlgFactory().createClause();
VPPhraseSpec verbPhrase = this.getNlgFactory().createVerbPhrase(verb);
......@@ -147,19 +266,31 @@ public abstract class ClauseGenerator {
return phrase;
}
public VPPhraseSpec generateModalVerbClause(String verb, boolean pluralVerb, String modal, String verbComplement){
VPPhraseSpec vPhrase;
vPhrase = this.getNlgFactory().createVerbPhrase("haber");
vPhrase.setFeature(Feature.MODAL, "poder");
vPhrase.addComplement("confusión");
return vPhrase;
}
public SPhraseSpec generateComplentiserClause(SPhraseSpec phrase1, String compliment, SPhraseSpec phrase2) {
public SPhraseSpec generateComplentiserClause(SPhraseSpec phrase1, String compliment, NLGElement phrase2) {
phrase2.setFeature(Feature.COMPLEMENTISER, compliment);
phrase1.addComplement(phrase2);
return phrase1;
}
public CoordinatedPhraseElement generateNoumsCoordinate(ArrayList<String> noums){
CoordinatedPhraseElement phrase = this.getNlgFactory().createCoordinatedPhrase();
for(String n: noums){
phrase.addCoordinate(n.toLowerCase());
}
return phrase;
}
public CoordinatedPhraseElement generateCoordinate(ArrayList<SPhraseSpec> phrases){
CoordinatedPhraseElement phrase = this.getNlgFactory().createCoordinatedPhrase();
for(SPhraseSpec p: phrases){
phrase.addCoordinate(p);
}
return phrase;
}
}
......@@ -5,13 +5,12 @@ import simplenlg.lexicon.english.XMLLexicon;
import simplenlg.realiser.english.Realiser;
public class ClauseGeneratorEn extends ClauseGenerator {
private final Realiser realiser;
private Realiser realiser;
public ClauseGeneratorEn() {
super(new XMLLexicon());
this.realiser = new Realiser(super.getLexicon());
super(new XMLLexicon());
this.realiser = new Realiser(new XMLLexicon());
}
public String getRealisation(NLGElement phrase) {
......
......@@ -6,13 +6,13 @@ import simplenlg.realiser.spanish.Realiser;
public class ClauseGeneratorEs extends ClauseGenerator {
private final Realiser realiser;
private Realiser realiser;
public ClauseGeneratorEs() {
super(new XMLLexicon());
this.realiser = new Realiser(super.getLexicon());
this.realiser = new Realiser(new XMLLexicon());
}
public String getRealisation(NLGElement phrase) {
return this.realiser.realiseSentence(phrase);
}
......
......@@ -6,13 +6,13 @@ import simplenlg.realiser.galician.Realiser;
public class ClauseGeneratorGl extends ClauseGenerator {
private final Realiser realiser;
private Realiser realiser;
public ClauseGeneratorGl() {
super(new XMLLexicon());
this.realiser = new Realiser(super.getLexicon());
this.realiser = new Realiser(new XMLLexicon());
}
public String getRealisation(NLGElement phrase) {
return this.realiser.realiseSentence(phrase);
}
......
......@@ -10,8 +10,8 @@ import java.util.ArrayList;
public interface ExplainerManager {
Explanation getGlobalExplanation(String token, String dataset, String algorithm, String language) throws IOException, NotFoundEx;
Explanation getGlobalExplanation(String token, String dataset, String algorithm, String language) throws IOException, NotFoundEx, FormatEx;
Explanation getConfusion(String token, String dataset, String algorithm, ArrayList<Consequent> consequents, String language) throws FormatEx, IOException, NotFoundEx;
Explanation getLocalExplanation(String token, String dataset, String algorithm, Classification classification, String language) throws FormatEx, IOException, NotFoundEx;
Explanation getLocalExplanation(String token, String dataset, String algorithm, ArrayList<Classification> classifications, String language) throws FormatEx, IOException, NotFoundEx;
}
package brunolopez.expliclas.explainer;
import brunolopez.expliclas.models.Antecedent;
import brunolopez.expliclas.models.Attribute;
import brunolopez.expliclas.models.Classification;
import brunolopez.expliclas.models.Consequent;
import brunolopez.expliclas.models.DatasetConfig;
import brunolopez.expliclas.models.GlobalConfig;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class InfoExtractor {
......@@ -13,12 +17,20 @@ public class InfoExtractor {
private DatasetConfig config;
private ConfusionAnalyzer analyzer;
private GlobalConfig global;
private ArrayList<Classification> classifications;
public InfoExtractor(DatasetConfig config, File input, GlobalConfig global) throws FileNotFoundException {
this.config = config;
this.analyzer = new ConfusionAnalyzer(input);
this.global = global;
}
public InfoExtractor(DatasetConfig config, File input, GlobalConfig global, ArrayList<Classification> classifications) throws FileNotFoundException {
this.config = config;
this.analyzer = new ConfusionAnalyzer(input);
this.global = global;
this.classifications = classifications;
}
public String getDatasetName() {
return this.config.getDataset();
......@@ -56,7 +68,7 @@ public class InfoExtractor {
List<Integer> cycle = this.analyzer.getLongestCycle();
ArrayList<Integer> mostConfused;
if (cycle.size() == 0) {
if (cycle.isEmpty()) {
return false;
} else if (cycle.size() <= this.global.getEnumLimit() && getConfusedConseqPercentage() <= this.global.getConfusionParam("few")) {
for (Integer i : cycle) {
......@@ -109,4 +121,63 @@ public class InfoExtractor {
return this.analyzer.getConfusionBetween(consequents.get(0).getMatrixPosition()-1, consequents.get(1).getMatrixPosition() - 1);
}
public int getNumAlternatives() {
return this.classifications.size();
}
public HashMap<String, ArrayList<String>> getAttributeLabels(int alternative){
HashMap<String, ArrayList<String>> list = new HashMap();
ArrayList<String> attributes;
Antecedent antecedent;
for(Attribute a: this.config.getAttributes()){
antecedent = this.classifications.get(alternative).getAntecedenById(a.getId());
if(antecedent != null){
if(antecedent.isCategoric() )
attributes = list.get(antecedent.getDecision().split(" is ")[1]);
else
attributes = list.get(this.config.getAttributeById(a.getId()).getPropertyById(antecedent.getProperty()).getName());
if(attributes == null){
attributes = new ArrayList();
attributes.add(a.getName());
} else {
attributes.add(a.getName());
}
list.put(this.config.getAttributeById(a.getId()).getPropertyById(antecedent.getProperty()).getName(), attributes);
}
}
return list;
}
public String getConsequent(int alternative){
return this.config.getConsequentById(this.classifications.get(alternative).getConsequent().getId()).getName();
}
public String branchProbabilityHigh(int alternative){
double percentage = this.classifications.get(alternative).getConsequent().getPercentageNode();
if(percentage >= this.global.getBranchProbabilityCut())
return this.global.getLabelBranchFor(percentage);
return null;
}
public String branchProbabilityLow(int alternative){
double percentage = this.classifications.get(alternative).getConsequent().getPercentageNode();
if(percentage < this.global.getBranchProbabilityCut())
return this.global.getLabelBranchFor(percentage);
return null;
}
}
package brunolopez.expliclas.models;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class Antecedent {
private String decision;
private Interval interval;
private String label;
private int property;
public Antecedent() {
}
public Antecedent(String decision, String label) {
public Antecedent(String decision) {
this.decision = decision;
this.label = label;
}
public Antecedent(String decision, Interval interval, String label) {
public Antecedent(String decision, Interval interval, int property) {
this.decision = decision;
this.interval = interval;
this.label = label;
this.property = property;
}
public String getDecision() {
......@@ -28,8 +29,8 @@ public class Antecedent {
return interval;
}
public String getLabel() {
return label;
public int getProperty() {
return property;
}
public void setDecision(String decision) {
......@@ -40,8 +41,12 @@ public class Antecedent {
this.interval = interval;
}
public void setLabel(String label) {
this.label = label;
public void setProperty(int property) {