/*********************************************************************** 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.Ritio; /** * <p>Title: Algorithm</p> * * <p>Description: It contains the implementation of the algorithm</p> * * * <p>Company: KEEL </p> * * @author Jesús Jiménez * @version 1.0 */ import java.io.IOException; import org.core.*; import java.util.*; 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 double calcula_entropia(int atributo, LinkedList<Integer> filas){ double[] fila; double valor; double valor_salida; double contador = 0; LinkedList<Double> valores_atributo = new LinkedList<Double>(); LinkedList<Double> valores_salida = new LinkedList<Double>(); LinkedList<Double> porcentajes = new LinkedList<Double>() ; LinkedList<LinkedList<Double>> porcentajes_salida = new LinkedList<LinkedList<Double>>() ; //Calculamos los posibles valores del atributo for(int i=0;i<filas.size();i++){ fila = train.getExample(filas.get(i)); valor = fila[atributo]; if(!valores_atributo.contains(valor)){ valores_atributo.add(valor); } } //Calculamos los posibles valores de la salida for(int i=0;i<filas.size();i++){ valor = train.getOutputAsInteger(i); if(!valores_salida.contains(valor)){ valores_salida.add(valor); } } //Calculamos todos los porcentajes for(int j=0;j<valores_atributo.size();j++){ //Para cada valor de la columna a estudio double porcentaje = 0; double nfilas = 0; valor = valores_atributo.get(j); //Cogemos el valor for(int i=0;i<filas.size();i++){ // y para cada fila if(train.getExample(filas.get(i))[atributo] == valor){ //contamos contador++; } } porcentaje = (Double)(contador/filas.size()); porcentajes.add(porcentaje); nfilas = contador; contador = 0; LinkedList<Double> lista_aux = new LinkedList<Double>(); for(int k=0;k<valores_salida.size();k++){ //Contamos ahora las salidas para el valor del atributo a estudio porcentaje = 0; valor_salida = valores_salida.get(k); for(int i=0;i<filas.size();i++){ if(train.getExample(filas.get(i))[atributo] == valor && train.getOutputAsInteger(filas.get(i)) == valor_salida){ contador++; //contamos } } porcentaje = (Double)(contador/nfilas); //filas en las que esté 'valor' lista_aux.add(porcentaje); contador=0; } porcentajes_salida.add(lista_aux); } //Ya tenemos lo necesario para calcular la entropia en porcentajes y en porcentajes_salida double entropia = 0; double aux = 0; double porcentaje = 0; double p = 0; for (int i=0;i<porcentajes.size();i++){ for (int j=0;j<porcentajes_salida.get(i).size();j++){ p = porcentajes_salida.get(i).get(j); if (p!=0) aux = -1*p*(Math.log10(p)/Math.log10(2)) + aux; //En aux acumulo lo del paréntesis } porcentaje = porcentajes.get(i); entropia = entropia + porcentaje*aux; //Multiplicamos y sumamos al resto aux = 0; } /*for (int i=0;i<porcentajes.size();i++){ System.out.println("Porcentaje "+porcentajes.get(i)); for (int j=0;j<porcentajes_salida.get(i).size();j++){ System.out.println("Porcentaje salida "+porcentajes_salida.get(i).get(j)); } System.out.println("--------------------------------"); }*/ return entropia; } private int calcula_maxima_entropia(LinkedList<Integer> filas, LinkedList<Integer> atributos){ int atrib_max = -1; double aux_entropia, entropia = -1; for(int atributo=0;atributo<atributos.size();atributo++){ aux_entropia = calcula_entropia(atributos.get(atributo), filas); if (aux_entropia > entropia){ atrib_max = atributos.get(atributo); entropia = aux_entropia; } } //System.out.println("El atributo con mayor entropia es el número "+atrib_max+" con una entropia de "+entropia); return atrib_max; } private boolean consistencia(LinkedList<Integer> filas, LinkedList<Integer> atributos,int R){ int contador = 0; for (int i=0;i<filas.size();i++){ int rule = filas.get(i); if(rule!=R && train.getOutputAsInteger(rule) != train.getOutputAsInteger(R)){ for (int j=0;j<atributos.size();j++){ int A = atributos.get(j); if(train.getExample(rule)[A]== train.getExample(R)[A]){ contador++; } } } if (contador==atributos.size()){ //System.out.println("Inconsistente!!!"); return false; } contador=0; } return true; } private TreeMap<Integer,LinkedList<Integer>> partition(LinkedList<Integer> filas, LinkedList<Integer> atributos, int menos_relevante_anterior, int level){ //LinkedList<LinkedList<Integer>> RS_filas, LinkedList<LinkedList<Integer>> RS_atributos){ TreeMap<Integer,LinkedList<Integer>> RS = new TreeMap<Integer,LinkedList<Integer>>(); boolean retain = false; if (level<train.getnInputs() && filas.size()>0){ int menos_relevante; menos_relevante = calcula_maxima_entropia(filas,atributos); LinkedList<Integer> remove_group = new LinkedList<Integer>(); LinkedList<Integer> retain_group = new LinkedList<Integer>(); LinkedList<Integer> atributos_retain_group; LinkedList<Integer> atributos_remove_group; if(menos_relevante_anterior>=0){ atributos.add(menos_relevante_anterior);//lo agregamos ahora, para que no afecte al cálculo de la máxima entropía retain=true; //Si lo agregamos es porque nos encontramos en un retain_group, por tanto activamos el flag, //necesario para saber contra que filas calculamos la consistencia } //##ahora vamos a dividir el grupo a su vez en retain y remove: atributos_retain_group = (LinkedList<Integer>) atributos.clone(); //El retain group mantiene todas las columnas atributos.remove((Integer)menos_relevante); //quitamos el menos relevante nuevo atributos_remove_group = (LinkedList<Integer>) atributos.clone(); //Al remove_group le quitamos el menos relevante //Calculamos ahora qué fila va a cada grupo: if(!retain){ //si no es retain_group (es remove_group) hacemos el consistencia() solo con las filas actuales for (int i=0;i<filas.size();i++){ //Para cada fila if (consistencia(filas,atributos,filas.get(i))){ remove_group.add(filas.get(i)); }else{ retain_group.add(filas.get(i)); } } }else{ //si es un retain group, llamamos a consistencia() con todas las filas LinkedList<Integer> todasfilas = new LinkedList<Integer>(); for(int j=0;j<train.getnData();j++){ todasfilas.add(j); } for (int i=0;i<filas.size();i++){ //Para cada fila de las actuales if (consistencia(todasfilas,atributos,filas.get(i))){ //comprobab si son consistentes con todas las filas del dataset original remove_group.add(filas.get(i)); }else{ retain_group.add(filas.get(i)); } } } level++; if (level == train.getnInputs()){ //Si hemos llegado al final, guardamos en RS for(int i=0;i<remove_group.size();i++){ RS.put(remove_group.get(i), atributos_remove_group); } for(int i=0;i<retain_group.size();i++){ //if(!RS.containsKey(retain_group.get(i))) RS.put(retain_group.get(i), atributos_retain_group); } }else{ LinkedList<Integer> atributos_aux = (LinkedList<Integer>)atributos_remove_group.clone(); //No mandamos el menos_relevante porque al ser un remove_group no lo necesitará más TreeMap<Integer,LinkedList<Integer>> RS1 = partition(remove_group,atributos_remove_group,-1,level); //Ahora en vez de mandar los 'atributos_retain_group', mandamos por un lado los del remove, y aparte el menos relevante //Así conseguimos que el menos relevante no se tenga en cuenta para calcular la entropía. //Después se unirán (porque 'menos_relevante' es > 0) y se continuará con normalidad. TreeMap<Integer,LinkedList<Integer>> RS2 = partition(retain_group,atributos_aux,menos_relevante,level); RS1.putAll(RS2); //Unimos RS1 con RS2 RS = (TreeMap<Integer,LinkedList<Integer>>) RS1.clone(); //Copiamos a RS } } return RS; } /** * 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 { //Todas las filas LinkedList<Integer> filas = new LinkedList<Integer>(); for(int i=0;i<train.getnData();i++){ filas.add(i); } //Todas las columnas LinkedList<Integer> atributos = new LinkedList<Integer>(); for(int i=0;i<train.getnInputs();i++){ atributos.add(i); } int level = 1; //Nivel inicial TreeMap<Integer,LinkedList<Integer>> RS; RS = partition(filas,atributos,-1,level); //###################A partir de las particiones obtenidas, generamos la base de reglas######## BaseReglas br = new BaseReglas(train); br.anadirReglas(RS); br.mostrarReglas(); //###################finalmente guardamos la base de reglas en fichero########### String output = new String(""); br.ficheroReglas(outputReglas,output); //###################Comprobamos con el fichero de validacion############# LinkedList<String> resultado_val = br.compruebaReglas(val); //###################Comprobamos con el fichero 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); } }