/***********************************************************************
This file is part of KEEL-software, the Data Mining tool for regression,
classification, clustering, pattern mining and so on.
Copyright (C) 2004-2010
F. Herrera (herrera@decsai.ugr.es)
L. S�nchez (luciano@uniovi.es)
J. Alcal�-Fdez (jalcala@decsai.ugr.es)
S. Garc�a (sglopez@ujaen.es)
A. Fern�ndez (alberto.fernandez@ujaen.es)
J. Luengo (julianlm@decsai.ugr.es)
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 3 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, see http://www.gnu.org/licenses/
**********************************************************************/
package keel.Algorithms.Rule_Learning.LEM2;
/**
* <p>Title: Algorithm</p>
*
* <p>Description: It contains the implementation of the algorithm</p>
*
*
* <p>Company: KEEL </p>
*
* @author Alberto Fernandez
* @version 1.0
*/
import java.io.IOException;
import org.core.*;
import java.util.*;
import keel.Dataset.Attribute;
import keel.Dataset.Attributes;
public class Algorithm {
myDataset train, val, test;
String outputTr, outputTst, outputReglas;
//int nClasses;
//We may declare here the algorithm's parameters
private boolean somethingWrong = false; //to check if everything is correct.
/**
* Default constructor
*/
public Algorithm() {
}
/**
* It reads the data from the input files (training, validation and test) and parse all the parameters
* from the parameters array.
* @param parameters parseParameters It contains the input files, output files and parameters
*/
public Algorithm(parseParameters parameters) {
train = new myDataset();
val = new myDataset();
test = new myDataset();
try {
System.out.println("\nReading the training set: " +
parameters.getTrainingInputFile());
train.readClassificationSet(parameters.getTrainingInputFile(), true);
System.out.println("\nReading the validation set: " +
parameters.getValidationInputFile());
val.readClassificationSet(parameters.getValidationInputFile(), false);
System.out.println("\nReading the test set: " +
parameters.getTestInputFile());
test.readClassificationSet(parameters.getTestInputFile(), false);
} catch (IOException e) {
System.err.println(
"There was a problem while reading the input data-sets: " +
e);
somethingWrong = true;
}
//We may check if there are some numerical attributes, because our algorithm may not handle them:
somethingWrong = somethingWrong || train.hasNumericalAttributes();
somethingWrong = somethingWrong || train.hasMissingAttributes();
outputTr = parameters.getTrainingOutputFile();
outputTst = parameters.getTestOutputFile();
outputReglas = parameters.getReglasOutputFile();
}
private LinkedList<TreeMap<Integer,Double>> calcula_lista_bloques_atributovalor(){
LinkedList<TreeMap<Integer,Double>> bloques_atributo_valor = new LinkedList<TreeMap<Integer,Double>>();
for (int i=0;i<train.getnData();i++){ //Para cada fila
TreeMap<Integer,Double> valor_atributo = new TreeMap<Integer,Double>();
for (int j=0;j<train.getnInputs();j++){ //Y para cada columna
//Guardamos la columna y su valor correspondiente
valor_atributo.put(j, train.getExample(i)[j]);
}
//añadimos todos los valores encontrados para la fila
bloques_atributo_valor.add(valor_atributo);
}
return bloques_atributo_valor;
}
private LinkedList<Atributo_valor> calcula_mapa_bloques_atributovalor(
LinkedList<TreeMap<Integer,Double>> bloques_atributo_valor){
LinkedList<Atributo_valor> lista_auxiliar = new LinkedList<Atributo_valor>();
for (int i=0;i<bloques_atributo_valor.size();i++){ //para cada fila de la tabla
Iterator iter = bloques_atributo_valor.get(i).keySet().iterator();
while(iter.hasNext()){//dentro de cada fila recorremos el mapa que acumula los atributos-valor
Integer atributo=(Integer) iter.next();//saca el valor de la columna
Double valor = bloques_atributo_valor.get(i).get(atributo);//saca el valor asociado
Atributo_valor av_nuevo = new Atributo_valor(atributo,valor);//crea un nuevo Atributo_valor
//si encuentra el valor repetido, devuelve ese valor para poder añadir en su lista,
//en caso contrario devuelve null, para poder añadir el Atributo_valor a la nueva LinkedList
Atributo_valor av_lista = av_nuevo.findElement(lista_auxiliar);
if (av_lista!=null){
av_lista.addFila(i);//añade a la lista del Atributo_valor repetido
}else{
av_nuevo.addFila(i);//añade a la lista del Atributo_valor
lista_auxiliar.add(av_nuevo);//añade el nuevo Atributo_valor
}
}
}
return lista_auxiliar;
}
private TreeMap<Integer,LinkedList<Double>> calcula_parejas_relevantes(LinkedList<Integer> G, LinkedList<TreeMap<Integer,Double>> bloques_atributo_valor){
TreeMap<Integer,LinkedList<Double>> parejas_relevantes = new TreeMap<Integer,LinkedList<Double>>();
TreeMap<Integer,Double> aux = new TreeMap<Integer,Double>();
int atributo;
double valor;
for(int i=0; i<G.size(); i++){ //Para cada valor de G
aux = bloques_atributo_valor.get(G.get(i)); //Cogemos la/s pareja/s
Iterator iter = aux.keySet().iterator();
while(iter.hasNext()){ //Para cada pareja.
atributo = (Integer) iter.next(); //Cogemos el atributo
valor = aux.get(atributo); //Cogemos el valor del atributo
if (!parejas_relevantes.containsKey(atributo)){ //Si el atributo no esta
//creamos la lista:
LinkedList<Double> lista_valores = new LinkedList<Double>();
//Anadimos el valor:
lista_valores.add(valor);
//Anadimos el atributo y la lista al mapa final:
parejas_relevantes.put(atributo,lista_valores ); //Añadimos el atributo
}else if (!parejas_relevantes.get(atributo).contains(valor)){ //Si el atributo está, pero no su valor
//Anadimos el valor a la lista del mapa final
parejas_relevantes.get(atributo).add(valor);
}//else{ /*Pareja repetida. No se añade*/}
}
}
return parejas_relevantes;
}
private Atributo_valor calcula_mejor_pareja(LinkedList<Integer> G, LinkedList<Atributo_valor> bloques_atributovalor, TreeMap<Integer,LinkedList<Double>> parejas_relevantes){
Atributo_valor resultado = new Atributo_valor();
int atributo; double valor;
int max=0;
int cardinalidad=0;
Iterator iter = parejas_relevantes.keySet().iterator();
while (iter.hasNext()){ //Para cada atributo de una pareja relevante
atributo = (Integer) iter.next();
for (int i=0;i<parejas_relevantes.get(atributo).size();i++){
valor = parejas_relevantes.get(atributo).get(i); //cogemos su valor
Atributo_valor pareja = new Atributo_valor(atributo,valor); //creamos la pareja
//Obtenemos en que filas aparece la pareja actual
LinkedList<Integer> filas = pareja.findElement(bloques_atributovalor).getListFilas();
pareja.addFilas((LinkedList<Integer>)filas.clone());
//Calculamos la interseccion con el conjunto G
int intersecciones = 0;
for (int j=0;j<filas.size();j++){
for (int k=0;k<G.size();k++){
if (filas.get(j).equals(G.get(k))) intersecciones++;
}
}
if(intersecciones > max){
max = intersecciones;
cardinalidad = filas.size();
resultado = pareja;
}else if(intersecciones == max){ //A igual n�mero de intersecciones, nos quedamos
//con el de menor cardinalidad
if (filas.size()<cardinalidad){
max = intersecciones;
cardinalidad = filas.size();
resultado = pareja;
}//Si tiene igual o peor cardinalidad, no hacemos nada y nos quedamos con
//el primero que apareci�
}
}
}
return resultado;
}
/**
* It launches the algorithm
*/
public void execute() {
if (somethingWrong) { //We do not execute the program
System.err.println("An error was found, either the data-set have numerical values or missing values.");
System.err.println("Aborting the program");
//We should not use the statement: System.exit(-1);
} else {
//##########Calculo de todos los bloques atributo-valor:################
LinkedList<TreeMap<Integer,Double>> bloques_atributo_valor = calcula_lista_bloques_atributovalor();
//#########Lo mismo que antes, pero en otra EEDD #######################
LinkedList<Atributo_valor> lista_bloques_atributo_valor = calcula_mapa_bloques_atributovalor(bloques_atributo_valor);
BaseReglas br = new BaseReglas();
Attribute s[] = Attributes.getOutputAttributes();
int numero_salidas = s[0].getNumNominalValues();
for (int pasada=0;pasada<numero_salidas;pasada++){
//######## Concepto B ##################################################
LinkedList<Integer> B = new LinkedList<Integer>();
for (int i = 0; i<train.getnData(); i++){
if(train.getOutputAsInteger(i)==pasada) B.add(i);
}
LinkedList<Integer> G = (LinkedList<Integer>) B.clone();
//################ Calculo de los complejos m�nimos
LinkedList<LinkedList<Atributo_valor>> complejos_minimos = new LinkedList<LinkedList<Atributo_valor>>();
TreeMap<Integer,LinkedList<Double>> parejas_relevantes = new TreeMap<Integer,LinkedList<Double>>();
LinkedList<Integer> interseccion = new LinkedList<Integer>();
LinkedList<Atributo_valor> lista_aux = new LinkedList<Atributo_valor>();
boolean subconjunto;
boolean vacio_interseccion = false;
//parejas_relevantes = calcula_parejas_relevantes(G, bloques_atributo_valor);
while (G.size()>0 && !vacio_interseccion){
//######Conjunto T(G) de todas las parejas relevantes valor-atributo es:
//System.out.println("Tam paraejas relevantes " +parejas_relevantes.size());
if (parejas_relevantes.size()==0) parejas_relevantes = calcula_parejas_relevantes(G, bloques_atributo_valor);
//En base a T(G) y a las parejas, calculamos la mejor pareja
Atributo_valor mejor_pareja = calcula_mejor_pareja(G, lista_bloques_atributo_valor, parejas_relevantes);
// if(mejor_pareja.getAtributo() != null) System.out.println("La mejor pareja es "+ mejor_pareja.getAtributo() +" -- "+mejor_pareja.getValor()+" -tama�o- "+mejor_pareja.getListFilas().size());
//Calculamos la interseccion entre la nueva pareja, y las obtenidas con anterioridad
if(mejor_pareja.getAtributo() != null){//Controla que T(G) != 0
if (lista_aux.size()==0){ //Si no hay ninguno, la interseccion sera todas las filas de la mejor pareja
interseccion =(LinkedList<Integer>) mejor_pareja.getListFilas().clone();
}else{
LinkedList<Integer> interseccion_aux = new LinkedList<Integer>();
for (int i=0;i<interseccion.size();i++){
//Si esta en los dos, pertenece a la interseccion
if (mejor_pareja.getListFilas().contains(interseccion.get(i))){
interseccion_aux.add(interseccion.get(i));
}
}
interseccion = (LinkedList<Integer>) interseccion_aux.clone();
}
//Ahora comprobamos que la interseccion sea subconjunto de B
subconjunto = true;
if (interseccion.size()==0){//si la interseccion vacion, no se considera subconjunto
subconjunto = false;
vacio_interseccion = true;
}
else{
for (int i=0;i<interseccion.size();i++){
if (!G.contains(interseccion.get(i))) subconjunto=false;
}
}
if(subconjunto){ //Si era subconjunto tenemos el primer complejo m�nimo
lista_aux.add(mejor_pareja);
complejos_minimos.add((LinkedList<Atributo_valor>) lista_aux.clone());
lista_aux.clear();
//Actualizamos G. Si queda vac�o acaba el algoritmo
for(int i=0;i<interseccion.size();i++){
G.remove((Integer) interseccion.get(i));
}
interseccion.clear();
parejas_relevantes.clear();
// System.out.println("Me he cargao las pareja, cuanto vale " +parejas_relevantes.size());
}else{
//apuntamos la pareja atributo_valor
lista_aux.add(mejor_pareja);
//borramos la pareja ya obtenida de las relevantes
parejas_relevantes.get(mejor_pareja.getAtributo()).remove((Double) mejor_pareja.getValor());
}
}else{
G.clear(); //como interseccion de T(G) no es subconjunto de B, forzamos la salida
}
}
for (int i=0;i<complejos_minimos.size();i++){
int j = 0;
//el while se ejecuta mientras el tamaño sea mayor de 1 o no haya comprobado todos los atributos
while(complejos_minimos.get(i).size()>1 && j<=complejos_minimos.get(i).size()){
Atributo_valor aux_av=complejos_minimos.get(i).removeFirst();
//Calcular la interseccion
LinkedList<Integer> inter = new LinkedList<Integer>();
for(int m=0;m<complejos_minimos.get(i).size();m++){
if (m==0){ //Si no hay ninguno, la interseccion sera todas las filas de la mejor pareja
inter =(LinkedList<Integer>) complejos_minimos.get(i).get(m).getListFilas();
}else{
LinkedList<Integer> interseccion_aux = new LinkedList<Integer>();
for (int n=0;n<inter.size();n++){
//Si est� en los dos, pertenece a la intersecci�n
if (complejos_minimos.get(i).get(m).getListFilas().contains(inter.get(n))){
interseccion_aux.add(inter.get(n));
}
}
inter = (LinkedList<Integer>) interseccion_aux.clone();
}
}
//Ahora comprobamos que la interseccion sea subconjunto de B
subconjunto = true;
for (int k=0;k<inter.size();k++){
if (!B.contains(inter.get(k))) subconjunto=false;
}
if (!subconjunto){//si no es subconjunto añadimos a la lista
complejos_minimos.get(i).addLast(aux_av);
j++;
}
}
}
//se añaden las reglas a la base de reglas a partir de los complejos mínimos obtenidos
br.anadirReglas(complejos_minimos, pasada);
}
//finalmente guardamos la base de reglas en fichero
String output = new String("");
br.ficheroReglas(outputReglas,output);
//###################Comprobamos con el fochero de validacion#############
LinkedList<String> resultado_val = br.compruebaReglas(val);
//###################Comprobamos con el fochero de test#############
LinkedList<String> resultado_test = br.compruebaReglas(test);
//Finally we should fill the training and test output files
doOutput(this.val, this.outputTr, resultado_val);
doOutput(this.test, this.outputTst, resultado_test);
System.out.println("Algorithm Finished");
}
}
/**
* It generates the output file from a given dataset and stores it in a file
* @param dataset myDataset input dataset
* @param filename String the name of the file
*/
private void doOutput(myDataset dataset, String filename, LinkedList<String> resultado) {
String output = new String("");
output = dataset.copyHeader(); //we insert the header in the output file
Double noacertados=0.0;
Double noclasificados=0.0;
//We write the output for each example
for (int i = 0; i < dataset.getnData(); i++) {
//for classification:
output += dataset.getOutputAsString(i) + " " +
resultado.get(i) + "\n";
if (resultado.get(i).compareTo("No clasificado") == 0){
noclasificados++;
}else if(dataset.getOutputAsString(i).compareTo(resultado.get(i)) != 0){
noacertados++;
}
}
Fichero.escribeFichero(filename, output);
}
}