Commit 7a01bfa3 authored by Bruno López Trigo's avatar Bruno López Trigo

Engadidas cabeceiras de licencia e actualizada documentación

parent 0e1c7d2b
/*
* Copyright (C) 2018 Bruno López Trigo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package brunolopez.expliclas.builder;
import brunolopez.expliclas.exceptions.ConflictEx;
......@@ -7,7 +25,10 @@ import brunolopez.expliclas.models.DatasetConfig;
import brunolopez.expliclas.models.Instance;
public interface BuilderManager {
public DatasetConfig buildModels(String token, String datasetName, String model, String[] options) throws ConflictEx, FormatEx, NotFoundEx;
public double classifyFURIA(String token, String datasetName, String[] options, Instance instance) throws FormatEx, NotFoundEx;
public DatasetConfig buildModels(String token, String datasetName, String model, String[] options)
throws ConflictEx, FormatEx, NotFoundEx;
public double classifyFURIA(String token, String datasetName, String[] options, Instance instance)
throws FormatEx, NotFoundEx;
}
/*
* Copyright (C) 2018 Bruno López Trigo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package brunolopez.expliclas.builder;
import java.io.File;
......@@ -156,15 +174,15 @@ public class BuilderManagerImpl implements BuilderManager {
double distance;
// Genera la configuración del experto
for (int i = 0; i < instancesLRN.numAttributes(); i++) {
log.println(" " + instancesLRN.attribute(i).name());
if (i != (instancesLRN.numAttributes() - 1)) {
/*
/*
*
* Para el caso de los atributos numéricos dividir el atributo en 3 intervalos
* idénticos con etiquetas (Low, Medium, High)
* idénticos con etiquetas (Low, Medium, High)
*
*/
if (instancesLRN.attribute(i).isNumeric()) {
......@@ -182,11 +200,11 @@ public class BuilderManagerImpl implements BuilderManager {
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));
}
/*
}
/*
*
* Para el caso de los atributos categóricos las etiquetas son los posibles valores
* del atributo
* Para el caso de los atributos categóricos las etiquetas son los posibles
* valores del atributo
*
*/
else {
......@@ -202,7 +220,7 @@ public class BuilderManagerImpl implements BuilderManager {
}
// Añadir a la configuración los consecuentes o clases del problema
for (int i = 0; i < instancesLRN.classAttribute().numValues(); i++) {
config.getConsequents().add(new Consequent((i + 1), instancesLRN.classAttribute().value(i),
......@@ -233,7 +251,6 @@ public class BuilderManagerImpl implements BuilderManager {
Evaluation evalLRN = new Evaluation(instancesLRN, null);
/*
*
* Evaluar el modelo usando un 10 cross-validation por defecto
......@@ -312,7 +329,7 @@ public class BuilderManagerImpl implements BuilderManager {
/*
*
* Construye el modelo de clasificación de WEKA para FURIA para clasificar una
* instancia concreta. Este método se utiliza para clasificar cuando se produce
* instancia concreta. Este método se utiliza para clasificar cuando se produce
* stretching, vote for the most frequent class o abstain.
*
*/
......@@ -351,7 +368,8 @@ public class BuilderManagerImpl implements BuilderManager {
}
}
// Especificamos que la instancia es del mismo tipo que las instancias de entrenamiento
// Especificamos que la instancia es del mismo tipo que las instancias de
// entrenamiento
wekaInstance.setDataset(instancesLRN);
// Especificamos una clase cualquiera de salida (en este caso la primera)
wekaInstance.setClassValue(instancesLRN.instance(0).classValue());
......
/*
* Copyright (C) 2018 Bruno López Trigo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package brunolopez.expliclas.classifiers;
import brunolopez.expliclas.exceptions.ConflictEx;
......
/*
* Copyright (C) 2018 Bruno López Trigo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package brunolopez.expliclas.classifiers;
import java.io.BufferedReader;
......@@ -22,116 +40,119 @@ import brunolopez.expliclas.utils.MapperJSON;
*/
public class MatrixBuilder {
private BufferedReader reader;
private final FileManager fmanager;
public MatrixBuilder(File input) throws FileNotFoundException {
this.reader = new BufferedReader(new FileReader(input));
this.fmanager = new FileManager();
}
/*
*
* Construcción de la matriz de cross-validation, se limita a la lectura
* del modelo de WEKA
*
*/
public Matrix readMatrix() throws IOException {
String line = "";
ArrayList<Integer> row = new ArrayList<>();
Matrix m = new Matrix();
while (!line.startsWith("=== Confusion")) {
line = this.reader.readLine();
}
for (int i = 0; i < 2; i++) {
this.reader.readLine();
}
line = this.reader.readLine().split(" \\| ")[0].trim();
while (line != null && !line.isEmpty()) {
for (String s : line.split("\\s+")) {
row.add(Integer.parseInt(s));
}
m.addRow(row);
row.clear();
line = this.reader.readLine();
if (line != null) {
line = line.split(" \\| ")[0].trim();
}
}
this.reader.close();
m.setPrecision();
return m;
}
/*
*
* Construcción de la matriz de confusión de entrenamiento y test, requiere de la lectura
* de los archivos de predicciones
*
*/
public Matrix buildMatrixInstances(String token, String name, String algorithm, String type, boolean abstain) throws NotFoundEx, IOException, FormatEx {
File predictions;
File configFile;
MapperJSON mapper = new MapperJSON();
Position p;
Matrix m;
try {
configFile = this.fmanager.getConfig(token, name, "en");
DatasetConfig config = mapper.readConfigJSON(configFile);
// Se obtienen las predicciones
if (type.equals("train")) {
predictions = this.fmanager.getPredictions(token, name, algorithm);
} else {
predictions = this.fmanager.getPredictionsTest(token, name, algorithm);
}
// Se crea una matriz, indicando se tiene columna de abstenciones o no
m = new Matrix(config.getConsequents().size(), abstain);
this.reader = new BufferedReader(new FileReader(predictions));
String line = reader.readLine();
int instance = 1;
while (line != null) {
// Si la predicción es "NaN" entonces hay una abstención
if(line.split(" ")[1].equals("NaN")) {
p = new Position((int) Float.parseFloat(line.split(" ")[0]), config.getConsequents().size());
} else {
p = new Position((int) Float.parseFloat(line.split(" ")[0]), (int) Float.parseFloat(line.split(" ")[1]));
}
// Si la predicción es incorrecta se añade a la lista de instancias confundidas la instancia
if (p.getRow() != p.getColumn()) {
m.addConfused(p, instance);
}
// Se incrementa en la matriz la posición correspondiente a la predicción
m.increment(p.getRow(), p.getColumn());
line = reader.readLine();
instance++;
}
} catch (Exception ex) {
throw new FormatEx("Something went wrong building " + type + " matrix");
}
m.setPrecision();
return m;
}
private BufferedReader reader;
private final FileManager fmanager;
public MatrixBuilder(File input) throws FileNotFoundException {
this.reader = new BufferedReader(new FileReader(input));
this.fmanager = new FileManager();
}
/*
*
* Construcción de la matriz de cross-validation, se limita a la lectura del
* modelo de WEKA
*
*/
public Matrix readMatrix() throws IOException {
String line = "";
ArrayList<Integer> row = new ArrayList<>();
Matrix m = new Matrix();
while (!line.startsWith("=== Confusion")) {
line = this.reader.readLine();
}
for (int i = 0; i < 2; i++) {
this.reader.readLine();
}
line = this.reader.readLine().split(" \\| ")[0].trim();
while (line != null && !line.isEmpty()) {
for (String s : line.split("\\s+")) {
row.add(Integer.parseInt(s));
}
m.addRow(row);
row.clear();
line = this.reader.readLine();
if (line != null) {
line = line.split(" \\| ")[0].trim();
}
}
this.reader.close();
m.setPrecision();
return m;
}
/*
*
* Construcción de la matriz de confusión de entrenamiento y test, requiere de
* la lectura de los archivos de predicciones
*
*/
public Matrix buildMatrixInstances(String token, String name, String algorithm, String type, boolean abstain)
throws NotFoundEx, IOException, FormatEx {
File predictions;
File configFile;
MapperJSON mapper = new MapperJSON();
Position p;
Matrix m;
try {
configFile = this.fmanager.getConfig(token, name, "en");
DatasetConfig config = mapper.readConfigJSON(configFile);
// Se obtienen las predicciones
if (type.equals("train")) {
predictions = this.fmanager.getPredictions(token, name, algorithm);
} else {
predictions = this.fmanager.getPredictionsTest(token, name, algorithm);
}
// Se crea una matriz, indicando se tiene columna de abstenciones o no
m = new Matrix(config.getConsequents().size(), abstain);
this.reader = new BufferedReader(new FileReader(predictions));
String line = reader.readLine();
int instance = 1;
while (line != null) {
// Si la predicción es "NaN" entonces hay una abstención
if (line.split(" ")[1].equals("NaN")) {
p = new Position((int) Float.parseFloat(line.split(" ")[0]), config.getConsequents().size());
} else {
p = new Position((int) Float.parseFloat(line.split(" ")[0]),
(int) Float.parseFloat(line.split(" ")[1]));
}
// Si la predicción es incorrecta se añade a la lista de instancias confundidas
// la instancia
if (p.getRow() != p.getColumn()) {
m.addConfused(p, instance);
}
// Se incrementa en la matriz la posición correspondiente a la predicción
m.increment(p.getRow(), p.getColumn());
line = reader.readLine();
instance++;
}
} catch (Exception ex) {
throw new FormatEx("Something went wrong building " + type + " matrix");
}
m.setPrecision();
return m;
}
}
/*
* Copyright (C) 2018 Bruno López Trigo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package brunolopez.expliclas.classifiers;
import java.io.File;
......@@ -68,12 +86,12 @@ public class RuleBuilder {
Rules rules = new Rules();
rules.setOptions(options);
/*
/*
*
* Detección de opciones importantes:
*
* -p: para determinar si la TNorm es producto o mínimo
* -s: para determinar la acción cuando no se activan reglas.
* -p: para determinar si la TNorm es producto o mínimo -s: para determinar la
* acción cuando no se activan reglas.
*
*/
for (int i = 0; i < options.length; i++) {
......@@ -107,26 +125,26 @@ public class RuleBuilder {
/*
*
* Expresión regular de intervalo numérico
*
* Grupo 1: atributo - Grupo 2: valores
*
* Expresión regular de intervalo numérico
*
* Grupo 1: atributo - Grupo 2: valores
*
*/
Pattern numericInterval = Pattern.compile("^\\((.*)\\sin\\s\\[(.*)\\]\\)$");
/*
*
* Expresión regular de intervalo categórico
*
* Grupo 1: atributo - Grupo 2: valor
*
* Expresión regular de intervalo categórico
*
* Grupo 1: atributo - Grupo 2: valor
*
*/
Pattern categoricInterval = Pattern.compile("^\\((.*)\\s=\\s(.*)\\)$");
/*
*
* Expresión regular de intervalo categórico
*
* Grupo 1: consecuente - Grupo 2: CF
*
* Expresión regular de intervalo categórico
*
* Grupo 1: consecuente - Grupo 2: CF
*
*/
Pattern outputClass = Pattern.compile("^.*=(.*)\\s\\(CF\\s=\\s(.*)\\)$");
......@@ -144,9 +162,9 @@ public class RuleBuilder {
rule = new Rule();
intervals = line.split(" and ");
for (int i = 0; i < intervals.length; i++) {
/*
* Si el intervalo contiene " => " estamos en el último
* por lo tanto separamos el intervalo de la clase de salida
/*
* Si el intervalo contiene " => " estamos en el último por lo tanto separamos
* el intervalo de la clase de salida
*/
if (intervals[i].contains(" => ")) {
interval = intervals[i].split(" => ")[0];
......@@ -167,9 +185,9 @@ public class RuleBuilder {
// Obtenemos los valores
values = numericMatch.group(2).split(", ");
/*
* Para los casos -inf, el valor es el valor mínimo del atributo.
* Para los casos inf, el valor es el máximo del atributo.
* El resto de casos toman el valor directamente
* Para los casos -inf, el valor es el valor mínimo del atributo. Para los casos
* inf, el valor es el máximo del atributo. El resto de casos toman el valor
* directamente
*/
if (values[0].equals("-inf")) {
component.setFirstFuzzyValue(
......@@ -196,21 +214,21 @@ public class RuleBuilder {
component.setFourthFuzzyValue(Double.parseDouble(values[3]));
}
/*
* Si el componente ya existía se realiza la intersección entre ambos componentes
* y se calculan las ecuaciones de las rectas.
* Si el componente ya existía se realiza la intersección entre ambos
* componentes y se calculan las ecuaciones de las rectas.
*/
if (aux != null) {
((NumericComponent) aux).makeIntersection((NumericComponent) component);
((NumericComponent) aux).calculateStraight();
rule.removeComponentById(aux.getAttribute().getId());
rule.addComponent(aux);
}
}
// Si el componente no existe se calculan las rectas y se añade
else {
((NumericComponent) component).calculateStraight();
rule.addComponent(component);
}
}
}
/*
* Para el intervalo categórico se crea el componente y se añade
*/
......@@ -239,7 +257,6 @@ public class RuleBuilder {
}
private VisualRules buildVisualRules(Rules rules) {
VisualRules vrules = new VisualRules();
......@@ -301,9 +318,8 @@ public class RuleBuilder {
/*
* Se añaden las coordenadas de la definición del intervalo, que pueden ser:
*
* - [A, 0], [B, 1], [C, 1], [D, 0]
* - [A, 1], [B, 1], [C, 1], [D, 0]
* - [A, 0], [B, 1], [C, 1], [D, 1]
* - [A, 0], [B, 1], [C, 1], [D, 0] - [A, 1], [B, 1], [C, 1], [D, 0] - [A, 0],
* [B, 1], [C, 1], [D, 1]
*/
vcomponent.addValue(new Coordinate(comp.getFirstFuzzyValue(),
((NumericComponent) comp).retrieveValue(comp.getFirstFuzzyValue())));
......@@ -316,9 +332,11 @@ public class RuleBuilder {
/*
* Si el componente está activo se establecen las coordenadas de activación:
*
* - [A, 0], [cutValue(rectaAB, activación), Yactivación], [cutValue(rectaCD, activación), activación], [D, 0]
* - [A, 0], [cutValue(rectaAB, activación), Yactivación], [cutValue(rectaCD,
* activación), activación], [D, 0]
*
* cutValue(recta, activación) devuelve la coordenada X donde la recta toma el valor activación
* cutValue(recta, activación) devuelve la coordenada X donde la recta toma el
* valor activación
*/
if (comp.getActivation() > 0) {
vcomponent.addActivationValue(new Coordinate(comp.getFirstFuzzyValue(),
......@@ -342,8 +360,8 @@ public class RuleBuilder {
vcomponent.addValue(new Coordinate(comp.getThirdFuzzyValue(), 1d));
vcomponent.addValue(new Coordinate(comp.getFourthFuzzyValue(), 0d));
/*
* Si el componente está activo, para este caso el valor es binario
* si no está activo será 0, si está activo será siempre 1. Entonces:
* Si el componente está activo, para este caso el valor es binario si no está
* activo será 0, si está activo será siempre 1. Entonces:
*
* - [A, 1], [B, 1], [C, 1], [D, 1]
*
......@@ -352,7 +370,7 @@ public class RuleBuilder {