/*********************************************************************** 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.Genetic_Rule_Learning.Ant_Miner; import keel.Dataset.*; import org.core.*; import java.util.*; import java.math.*; import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; import java.io.IOException; import java.io.FileNotFoundException; /** * <p>T�tulo: Ant Colony Optimization</p> * <p>Descripci�n: Algoritmo de clasificacion por ACO</p> * <p>Copyright: Copyright (c) 2007</p> * <p>Empresa: </p> * @author Vicente Rub�n del Pino Ruiz * @version 1.0 */ public class ACO { private float[][] feromona; //Aqui se almacenara la feromona para cada valor de cada atributo private int[] numeroValores; //Vector que guarda el numero de valores de cada atributo private float[][] funcionN; //Matriz con los valores N de esta manera no se vuelven a calcular private float[][] funcionH; //Matriz con todos los valores H +preprocesamiento private Vector listaValores; //Aqui se almacenaran los distintos valores que puede alcanzar cada valor (ordenados de menor a mayor) private Vector listaValoresRestantes; //Aqui se iran almacenando los valores asignables a la hormiga private Vector listaClases; //Vector de nombres de cada clase private Vector reglasDescubiertas; //Reglas descubiertas por las hormigas, inicialmente vacio private Vector reglasHormigas; //Reglas descubiertas por las hormigas en una iteracion del while private ConjuntoDatos cTrain; // Muestras del fichero de entrenamiento preprocesado private ConjuntoDatos cTrainC; //Muestras del fichero de entrenamiento sin procesamiento previo private ConjuntoDatos cTest; //Muestras del fichero de prueba private ConjuntoDatos muestrasCubiertas; //Muestras que han sido cubiertas por las reglas creadas private int numHormigas; private int maximoDatosSinCubrir; private int minimoCasosRegla; private int maxIteracionesSinConverger; private int numAtributos; private long semilla; private float porcentajeTrain; private float porcentajeTest; private String fInTrainP; private String fInTrainC; private String fInTest; private String fOutTrain; private String fOutTest; private String fOutResult; private String cabeceraTrain; private String cabeceraTest; boolean continuosValues; //Indica si hay que comprobar si los datos son compatibles con el algoritmo /** * Constructor por defecto (no hace nada) */ public ACO() { } /** * All is OK is the data-sets have not got any continuos values * @return boolean a flag for the existence of continous values in the data-set */ public boolean OK(){ return (!continuosValues); } /** * Constructor de una instancia del algoritmo con los ficheros de datos y * umbrales definidos por el usuario * * @param fTrainPrep String Nombre del fichero de entrenamiento con preprocesamiento * @param fTrain String Nombre del fichero de entrenamiento entero para validaci�n * @param fTestOriginal String Nombre del fichero de prueba * @param fSalidaTrain String Nombre del fichero de salida para las pruebas al fichero de entrenamiento * @param fSalidaTest String Nombre del fichero de salida para las pruebas al fichero de test * @param fSalidaResult String Nombre del fichero donde se guardaran los resultados globales. * @param nHormigas int Numero de hormigas en el algoritmo * @param maxDatos int Maximo de datos sin cubrir por reglas * @param minCasos int Minimo de casos que debe cubrir una regla creada * @param maxIter int Maximo de iteraciones sin que haya convergencia * @param semillaOriginal long Semilla para el generador de numeros aleatoreos */ public ACO(String fTrainPrep, String fTrain, String fTestOriginal, String fSalidaTrain, String fSalidaTest, String fSalidaResult, int nHormigas, int maxDatos, int minCasos, int maxIter, long semillaOriginal) { numHormigas = nHormigas; maximoDatosSinCubrir = maxDatos; minimoCasosRegla = minCasos; maxIteracionesSinConverger = maxIter; semilla = semillaOriginal; fInTrainP = new String(fTrainPrep); fInTrainC = new String(fTrain); fInTest = new String(fTestOriginal); fOutTrain = new String(fSalidaTrain); fOutTest = new String(fSalidaTest); fOutResult = new String(fSalidaResult); cabeceraTest = new String(""); cabeceraTrain = new String(""); listaValores = new Vector(); listaValoresRestantes = new Vector(); listaClases = new Vector(); reglasDescubiertas = new Vector(); reglasHormigas = new Vector(); extraeDatos(); //Una vez asignadas las caracteristicas extraemos los datos de los ficheros } /** * Modulo que extrae los datos de los tres ficheros (train, train entero y test) y * los inserta en conjunto de datos con un formato conocido por el algoritmo */ private void extraeDatos() { continuosValues = false; myDataset dTrain = new myDataset(); myDataset dTrainC = new myDataset(); myDataset dTest = new myDataset(); try { dTrain.readClassificationSet(fInTrainP, true); if (dTrain.hayAtributosContinuos()) { System.err.println( "Ant_Miner may not handle continuous attributes.\nPlease discretize the data-set"); continuosValues = true; } dTrainC.readClassificationSet(fInTrainC, false); if (dTrainC.hayAtributosContinuos()) { System.err.println( "Ant_Miner may not handle continuous attributes.\nPlease discretize the data-set"); continuosValues = true; } dTest.readClassificationSet(fInTest, false); } catch (IOException e) { System.err.println("Problema leyendo los conjuntos de datos:"); System.err.println("-> " + e); System.exit(0); } creaDatos(); cTrain = extraeMuestrasSinP(dTrain); cTrainC = extraeMuestrasSinP(dTrainC); cTest = extraeMuestrasSinP(dTest); cabeceraTrain = dTrainC.copyHeader(); cabeceraTest = dTest.copyHeader(); } /** * Funcion que extrae los datos de un dataset y los introduce en un conjunto de * datos * @param original myDataset myDataset del que se extraen los datos * @return ConjuntoDatos Conjunto de datos donde se devuelve con el formato conocido por el algoritmo */ private ConjuntoDatos extraeMuestras(myDataset original) { double[][] X; int[] C; int nDatos; int nAtributos; Atributo at; Muestra mt; Vector muestras = new Vector(); ConjuntoDatos devolver; X = original.getX(); C = original.getC(); nDatos = original.getndatos(); nAtributos = original.getnentradas(); Attribute[] atv = Attributes.getInputAttributes(); //Construimos el Conjunto de Datos con los datos ya preprocesados muestras = new Vector(); for (int i = 0; i < nDatos; i++) { mt = new Muestra(); for (int j = 0; j < nAtributos; j++) { if (X[i][j] == -1) { System.err.println( "El algoritmo no admite valores perdidos"); System.exit(0); //El algoritmo no admite valores perdidos } at = (Atributo) ((Vector) listaValores.get(j)).get((int) X[i][j]); //Cogemos el puntero que se�ala al atributo almacenado en lista de valores mt.insertarAtributo(at); } at = (Atributo) listaClases.get(C[i]); mt.insertaPosicion(i); mt.insertarClase(at); muestras.addElement(mt); } devolver = new ConjuntoDatos(muestras); return devolver; } /** * Funcion que extrae los datos de un dataset sin preprocesar y los introduce * en un conjunto de datos * @param original myDataset myDataset del que se extraen los datos * @return ConjuntoDatos Conjunto de datos donde se devuelve con el formato conocido por el algoritmo */ private ConjuntoDatos extraeMuestrasSinP(myDataset original) { double[][] X; int[] C; int nDatos; int posicion; int nAtributos; Atributo at; Muestra mt; Vector muestras = new Vector(); ConjuntoDatos devolver; X = original.getX(); C = original.getC(); nDatos = original.getndatos(); nAtributos = original.getnentradas(); Attribute[] atv = Attributes.getInputAttributes(); Attribute atD; //Construimos el Conjunto de Datos con los datos ya preprocesados muestras = new Vector(); for (int i = 0; i < nDatos; i++) { mt = new Muestra(); for (int j = 0; j < nAtributos; j++) { if (X[i][j] == -1) { System.err.println( "El algoritmo no admite valores perdidos"); System.exit(0); //El algoritmo no admite valores perdidos } posicion = (int) X[i][j]; atD = atv[j]; if (atD.getType() == 1) { posicion = posicion - 1; //En los enteros se empieza a contar desde 1 y el vector desde 0 [0,9] = [1,10] } //System.out.println("------->"+X[i][j]+" "+posicion+" "+i+" "+j); at = (Atributo) ((Vector) listaValores.get(j)).get(posicion); //Cogemos el puntero que se�ala al atributo almacenado en lista de valores mt.insertarAtributo(at); } at = (Atributo) listaClases.get(C[i]); mt.insertaPosicion(i); mt.insertarClase(at); muestras.addElement(mt); } devolver = new ConjuntoDatos(muestras); return devolver; } /** * Modulo que crea las lista de datos necesarias para el funcionamiento del algoritmo * entre ellas estan, la lista de distintos valores que puede tomar cada atributo * y la lista de distintos valores de salida que puede tomar la clase */ private void creaDatos() { Attribute[] listaAtributos; Attribute actual; Atributo insertar; Vector valores; Vector nombres; int maximo; int minimo; String nombre; //Crear lista de valores listaAtributos = Attributes.getInputAttributes(); numAtributos = listaAtributos.length; numeroValores = new int[numAtributos]; //inicializamos el vector con el numero de valores de cada atibuto for (int i = 0; i < listaAtributos.length; i++) { valores = new Vector(); actual = listaAtributos[i]; if (actual.getType() == 1) { //El tipo del atributo es entero otra forma de coger sus valores maximo = (int) actual.getMaxAttribute(); minimo = (int) actual.getMinAttribute(); numeroValores[i] = (maximo - minimo) + 1; //Numero de valores de este atributo for (int j = minimo; j <= maximo; j++) { insertar = new Atributo(String.valueOf(j), i); valores.addElement(insertar); } } else { //El tipo del atributo es nominal nombres = actual.getNominalValuesList(); for (int j = 0; j < nombres.size(); j++) { insertar = new Atributo((String) nombres.get(j), i); valores.addElement(insertar); } numeroValores[i] = nombres.size(); //Numero de valores de este atributo } listaValores.addElement(valores); } //Crear lista de nombres de clases actual = Attributes.getOutputAttribute(0); //Solo tenemos un atributo de salida en esta clasificacion nombres = actual.getNominalValuesList(); for (int i = 0; i < nombres.size(); i++) { insertar = new Atributo((String) nombres.get(i), -1); listaClases.addElement(insertar); } //Creamos la lista de valores H funcionH = new float[numAtributos][]; //Creamos la lista de valores N funcionN = new float[numAtributos][]; for (int i = 0; i < numAtributos; i++) { funcionN[i] = new float[numeroValores[i]]; funcionH[i] = new float[numeroValores[i]]; } } /** * Modulo que inicializa los valores que puede escoger una hormiga para incorporarlos a * su regla en construccion */ private void inicializaValoresRestantes() { listaValoresRestantes = new Vector(listaValores); } /** * Elimina el atributo que ya ha sido seleccionado junto con todos sus posibles valores * para que en la siguiente iteracion, la hormiga no los puedan seleccionar * @param eliminar Atributo Atributo que se quiere eliminar de la lista de valores restantes */ private void eliminaAtributoColumna(Atributo eliminar) { int indice; indice = eliminar.getAtributo(); listaValoresRestantes.set(indice, null); } /** * Modulo que ejecuta el algoritmo */ public void run() { //Conjunto de entrenamiento esta ya inicializado //Reglas descubiertas = {} ya esta hecho //Partimos todos los datos escritos hasta ahora System.out.println( "-----------------------------------------------------"); int hormigaActual; int convergencia; Randomize generadorA; //Para los numeros aleatoreos generadorA = new Randomize(); generadorA.setSeed(semilla); Regla hormiga; Regla mejor; Regla anterior = null; ComparadorRegla c; creaMatrizN(); while (cTrain.tamanio() > maximoDatosSinCubrir) { hormigaActual = 0; convergencia = 1; reglasHormigas = new Vector(); creaMatrizFeromona(); do { inicializaValoresRestantes(); //Inicializa un vector de atributos con todos los atributos escogibles por la hormiga hormiga = new Regla(); //Creamos una regla con la hormiga creaRegla(hormiga, generadorA); //Poda la regla podaRegla(hormiga); //Actualizamos feromona actualizarFeromona(hormiga); //Comprobamos la convergencia if (hormiga.esIgual(anterior)) { convergencia++; } else { reglasHormigas.addElement(hormiga); convergencia = 1; anterior = hormiga; } //Aumentamos el numero de hormigas que han generado una regla hormigaActual++; } while (hormigaActual < numHormigas && convergencia < maxIteracionesSinConverger); //Ordenamos las reglas de las hormigas de mayor calidad a menor c = Regla.obtenerComparador(); Collections.sort(reglasHormigas, c); //A�ade la mejor regla al conjunto de reglas descubiertas mejor = (Regla) reglasHormigas.get(0); reglasDescubiertas.addElement(mejor); //Quitar del conjunto de entrenamiento los casos cubiertos quitarCasosCubiertos(mejor); System.out.println("MEJOR REGLA DE LA ITERACION"); mejor.imprime(); System.out.println("Quedan " + cTrain.tamanio() + " muestras"); } //Crear regla por defecto Regla generica; generica = creaReglaGenerica(); reglasDescubiertas.addElement(generica); } /** * Funcion que crea una regla por defecto en caso de no aplicarse cualquiera * de las creadas por el algoritmo * @return Regla Regla por defecto que asigna una clase a cualquier muestra */ private Regla creaReglaGenerica() { Regla devolver = new Regla(); int mayorClase = cTrain.obtenerMayorClase(listaClases); //Obtenemos la clase mas repetida entre las muestras Atributo clase = (Atributo) listaClases.get(mayorClase); //Regla sin condiciones pero con clase devolver.insertarClase(clase); return devolver; } /** * Modulo que crea la matriz con valores de entropia para la funcion de * probabilidad. */ private void creaMatrizN() { double[] probabilidades; int numValores; Atributo actual; //Primero obtenemos la funcion H que es necesaria para hacer N for (int i = 0; i < numAtributos; i++) { numValores = numeroValores[i]; for (int j = 0; j < numValores; j++) { funcionH[i][j] = obtenerFuncionH(i, j); } } //Con la funcion H averiguada obtenemos n for (int i = 0; i < numAtributos; i++) { numValores = numeroValores[i]; for (int j = 0; j < numValores; j++) { funcionN[i][j] = calculaNij(i, j); } } } /** * Modulo que saca a los ficheros predefinidos los resultados obtenidos * por el algoritmo. */ public void sacaResultadosAFicheros() { File fichero; FileOutputStream flujo; PrintStream salida; int tamanioConjunto; int tamanioReglas; Muestra mt; Regla regla; Atributo clasePredicha = null; Atributo claseOriginal; boolean terminado = false; porcentajeTrain = 0; porcentajeTest = 0; //Primero sacamos los datos de TRAIN try { fichero = new File(fOutTrain); //Abrimos el fichero de salida para Train flujo = new FileOutputStream(fichero); //Enganchamos el flujo con el fichero salida = new PrintStream(flujo); //Asignamos el flujo a salida; salida.print(cabeceraTrain); //Ahora imprimimos todos las clases tamanioReglas = reglasDescubiertas.size(); tamanioConjunto = cTrainC.tamanio(); //Rotamos todas las muestras for (int i = 0; i < tamanioConjunto; i++) { mt = cTrainC.obtenerMuestra(i); //Rotamos todas las reglas terminado = false; for (int j = 0; j < tamanioReglas && !terminado; j++) { regla = (Regla) reglasDescubiertas.get(j); clasePredicha = regla.prediccion(mt); if (clasePredicha != null) { terminado = true; } } claseOriginal = mt.getClase(); salida.print(claseOriginal.getValor() + " "); salida.println(clasePredicha.getValor()); if (claseOriginal.equals(clasePredicha)) { porcentajeTrain++; } } porcentajeTrain = porcentajeTrain / tamanioConjunto; } catch (FileNotFoundException e) { System.err.println("El fichero " + fOutTrain + " no se pudo crear"); System.exit(0); } //Datos de Test try { fichero = new File(fOutTest); //Abrimos el fichero de salida para Train flujo = new FileOutputStream(fichero); //Enganchamos el flujo con el fichero salida = new PrintStream(flujo); //Asignamos el flujo a salida; salida.print(cabeceraTest); //Ahora imprimimos todos las clases tamanioReglas = reglasDescubiertas.size(); tamanioConjunto = cTest.tamanio(); //Rotamos todas las muestras for (int i = 0; i < tamanioConjunto; i++) { mt = cTest.obtenerMuestra(i); //Rotamos todas las reglas terminado = false; for (int j = 0; j < tamanioReglas && !terminado; j++) { regla = (Regla) reglasDescubiertas.get(j); clasePredicha = regla.prediccion(mt); if (clasePredicha != null) { terminado = true; } } claseOriginal = mt.getClase(); salida.print(claseOriginal.getValor() + " "); salida.println(clasePredicha.getValor()); if (clasePredicha.equals(claseOriginal)) { porcentajeTest++; } } porcentajeTest = porcentajeTest / tamanioConjunto; } catch (FileNotFoundException e) { System.err.println("El fichero " + fOutTest + " no se pudo crear"); System.exit(0); } } /** * Modulo que muestra los resultados del algoritmo por pantalla. * Muestra las reglas descubiertas seguido de el porcentaje de acierto * en los conjuntos de pruebas y test */ public void muestraResultados() { Regla regla; float porcentajeTrn = 0; float porcentajeTst = 0; int i; int tamanioTrain = cTrainC.tamanio(); int tamanioTst = cTest.tamanio(); Atributo clase; double mediaCondiciones = 0; int numReglas; File fichero; FileOutputStream flujo; PrintStream salida = null; try { fichero = new File(fOutResult); //Abrimos el fichero de salida para Train flujo = new FileOutputStream(fichero); //Enganchamos el flujo con el fichero salida = new PrintStream(flujo); //Asignamos el flujo a salida; } catch (FileNotFoundException e) { System.err.println("El fichero " + fOutResult + " no se pudo crear"); System.exit(0); } System.out.println("-------------------------------------------------"); System.out.println("Reglas descubiertas "); numReglas = reglasDescubiertas.size(); for (i = 0; i < reglasDescubiertas.size() - 1; i++) { //La regla generica se ense�a despues regla = (Regla) reglasDescubiertas.get(i); regla.ordenaAtributos(); regla.imprime(); salida.print("REGLA " + i + " : "); regla.imprimeFichero(salida); salida.println(); mediaCondiciones += regla.listaCondiciones().size(); } //Regla generica System.out.println("Regla generica:"); salida.print("REGLA DEFAULT: "); regla = (Regla) reglasDescubiertas.get(i); regla.ordenaAtributos(); clase = regla.obtenerReglaPredicha(); System.out.println("< All > ==> " + clase.getValor()); salida.println("< ALL > ==> " + clase.getValor()); mediaCondiciones++; System.out.println("Porcentaje sobre Train: " + porcentajeTrain); System.out.println("Porcentaje sobre Test: " + porcentajeTest); System.out.println("Numero de reglas: " + numReglas); System.out.println("Numero medio de condiciones: " + mediaCondiciones / numReglas); salida.println("Porcentaje sobre Train: " + porcentajeTrain); salida.println("Porcentaje sobre Test: " + porcentajeTest); salida.println("Numero de reglas: " + numReglas); salida.println("Numero medio de condiciones: " + mediaCondiciones / numReglas); } /** * Modulo que elimina los casos cubiertos por la regla del conjunto de entrenamiento * @param regla Regla Regla que cubre las muestras eliminadas del conjunto * de entrenamiento */ private void quitarCasosCubiertos(Regla regla) { cTrain.eliminaMuestrasCubiertas(regla); } /** * Modulo que poda la regla una vez se ha creado esta. * @param regla Regla Regla a podar por el modulo. */ private void podaRegla(Regla regla) { int numCondiciones; Regla reglaModificada; Atributo eliminar = null; Atributo mejoraCalidad = null; Atributo claseMejoraC = null; float calidadMejorada; float calidadActual; float calidadOriginal; Vector atributos; Atributo clase; boolean mejora = true; int numAtributos; int i; float muestrasCubiertas; numCondiciones = regla.obtenerNumCondiciones(); while (numCondiciones > 1 && !mejora) { //Cogemos la lista de atributos de la regla atributos = regla.listaCondiciones(); numAtributos = atributos.size(); //Cogemos la calidad que tiene la regla actual calidadOriginal = regla.obtenerCalidad(); //Ponemos a 0 la calidad mejorada calidadMejorada = 0; //De esta manera al terminar el for si no se ha entrado en el if no se elimina atributo //Iteramos por todas las condiciones que tiene la regla for (i = 0; i < numAtributos; i++) { //Cogemos el candidato a eliminar eliminar = (Atributo) atributos.get(i); //lo eliminamos del vector atributos.remove(i); //Creamos la nueva regla con los atributos restantes reglaModificada = new Regla(); reglaModificada.insertaAtributos(atributos); clase = obtenerClaseMasAdecuada(reglaModificada); reglaModificada.insertarClase(clase); //Obtenemos la calidad de la nueva regla calidadActual = obtenerCalidadRegla(reglaModificada); if (calidadActual > calidadOriginal) { //En caso de mejorar a la regla actual guardamos el atributo a eliminar mejoraCalidad = eliminar; //Y la calidad para evitar calcularla de nuevo calidadMejorada = calidadActual; claseMejoraC = clase; } else { atributos.insertElementAt(eliminar, i); } } //Una vez fuera del for comprobamos si se mejora la calidad if (calidadMejorada > calidadOriginal) { regla.eliminaCondicion(mejoraCalidad); regla.insertarClase(claseMejoraC); regla.asignarCalidad(calidadMejorada); } else { //En caso contrario salimos del bucle mejora = false; } } muestrasCubiertas = obtenerCalidadRegla2(regla); regla.asignarMuestrasCubiertas(muestrasCubiertas); //calidadMejorada=obtenerCalidadRegla(regla); //regla.asignarCalidad(calidadMejorada); } /** * Modulo que actualiza la feromona de la matriz de feromonas siguiendo * las condiciones usadas por la regla * @param regla Regla Regla que contiene las condiciones con las que se actualizara la feromona */ private void actualizarFeromona(Regla regla) { //Crear una lista donde se guardan los atributos Vector condiciones = regla.listaCondiciones(); int numCondiciones = condiciones.size(); Atributo condicion = null; Atributo valor; Vector valores; boolean terminado = false; float calidadAsignar; int atributo = 0; int numValores; int contador; int j = 0; int maximoContador; float sumatoriaCamino = 0; //Feromona de todos los atributos que se incrementan //Primero aumentar feromona //Por cada condicion buscar y aumentar for (int i = 0; i < numCondiciones; i++) { condicion = (Atributo) condiciones.get(i); atributo = condicion.getAtributo(); valores = (Vector) listaValores.get(atributo); numValores = valores.size(); j = 0; terminado = false; while (j < numValores && !terminado) { valor = (Atributo) valores.get(j); if (valor.esIgual(condicion)) { terminado = true; } else { j++; } } //Una vez los tenemos obtenemos su calidad!! calidadAsignar = regla.obtenerCalidad(); //float antes; //antes=feromona[atributo][j]; feromona[atributo][j] += feromona[atributo][j] * calidadAsignar; //Actualizamos la feromona del atributo en cuestion //if(Float.isInfinite(feromona[atributo][j])){ // System.out.println("Error en la feromona"+ calidadAsignar+" "+antes); // System.exit(0); //} sumatoriaCamino = sumatoriaCamino + feromona[atributo][j]; } //En el resto evaporar feromona for (int i = 0; i < numAtributos; i++) { numValores = numeroValores[i]; valores = (Vector) listaValores.get(i); for (int k = 0; k < numValores; k++) { condicion = (Atributo) valores.get(k); if (!condiciones.contains(condicion)) { feromona[i][k] = feromona[i][k] / sumatoriaCamino; } } } } /** * Crea una regla de acuerdo a las muestras que quedan sin cubrir * @param regla Regla Regla creada que es devuelta por referencia * @param generadorA Randomize Generador de numeros aleatorios */ private void creaRegla(Regla regla, Randomize generadorA) { int numMuestrasCubiertas = cTrain.tamanio(); //Antes de a�adir terminos a la regla, esta cubre todos los datos int atributosUsados = 0; //Numero de atributos que se han a�adido a la regla float calidadRegla; Atributo siguiente; //Siguiente atributo a a�adir a la regla Atributo clase; //Clase que se asigna a la regla de que se han a�adido todos los atributos Regla reglaTemporal = new Regla(regla); while (atributosUsados <= numAtributos && numMuestrasCubiertas >= maximoDatosSinCubrir) { //Comprobacion de si se puede seguir escogiendo atributos o no siguiente = escogeSiguienteAtributo(generadorA, reglaTemporal); //Nunca sera repetido reglaTemporal.insertarAtributo(siguiente); eliminaAtributoColumna(siguiente); //Elimina valores para el atributo insertado atributosUsados++; //Un atributo usado mas //--------------------------- //Asignar clase a la regla clase = obtenerClaseMasAdecuada(reglaTemporal); //Asignar calidad a la regla reglaTemporal.insertarClase(clase); //--------------------------- numMuestrasCubiertas = muestrasCubiertasPor(reglaTemporal); if (numMuestrasCubiertas >= maximoDatosSinCubrir || atributosUsados == 1) { regla.insertarAtributo(siguiente); regla.insertarClase(clase); } } //Asignar clase a la regla clase = obtenerClaseMasAdecuada(regla); //Asignar calidad a la regla regla.insertarClase(clase); calidadRegla = obtenerCalidadRegla(regla); regla.asignarCalidad(calidadRegla); } /** * Funcion que calcula la calidad de la regla que se le pasa por parametro * @param regla Regla Regla a la cual se le calculara la calidad * @return float Calidad de la regla */ private float obtenerCalidadRegla(Regla regla) { float calidad; float TP = 0, TN = 0, FP = 0, FN = 0; Muestra mt; Atributo clasePredicha; Atributo claseReal; clasePredicha = regla.obtenerReglaPredicha(); for (int i = 0; i < cTrain.tamanio(); i++) { mt = cTrain.obtenerMuestra(i); claseReal = mt.getClase(); if (regla.estanAtributosEn(mt)) { //TP Y FP if (claseReal.esIgual(clasePredicha)) { TP++; } else { FP++; } } else { //FN Y TN if (claseReal.esIgual(clasePredicha)) { FN++; } else { TN++; } } } calidad = (TP / (TP + FN)) * (TN / (FP + TN)); if (TP == 0 || TP + FN == 0 || TN == 0 || TN + FP == 0) { //Evitamos el numero infinito calidad = 0; } return calidad; } /** * Funcion que calcula la calidad de la regla que se le pasa por parametro * @param regla Regla Regla a la cual se le calculara la calidad * @return float Calidad de la regla */ private float obtenerCalidadRegla2(Regla regla) { float calidad; float TP = 0, FN = 0; Muestra mt; Atributo clasePredicha; Atributo claseReal; clasePredicha = regla.obtenerReglaPredicha(); for (int i = 0; i < cTrain.tamanio(); i++) { mt = cTrain.obtenerMuestra(i); claseReal = mt.getClase(); if (regla.estanAtributosEn(mt)) { //TP Y FP if (claseReal.esIgual(clasePredicha)) { TP++; } } else { //FN Y TN if (claseReal.esIgual(clasePredicha)) { FN++; } } } calidad = (TP / (TP + FN)); if (TP == 0 || TP + FN == 0) { //Evitamos el numero infinito calidad = 0; } return calidad; } /** * Funcion que devuelve la clase mas adecuada para el conjunto de condiciones * que ya se han asignado a la regla. * @param regla Regla Regla que contiene el conjunto de condiciones a las que se * les busca clase * @return Atributo Clase mas adecuada para las condiciones */ private Atributo obtenerClaseMasAdecuada(Regla regla) { Atributo clase; Muestra mt; Atributo claseMt; int mejor = 0; int actual = 0; boolean terminado = false; int numClases = listaClases.size(); int[] contadores = new int[numClases]; for (int j = 0; j < numClases; j++) { contadores[j] = 0; } for (int i = 0; i < cTrain.tamanio(); i++) { mt = cTrain.obtenerMuestra(i); if (regla.estanAtributosEn(mt)) { claseMt = mt.getClase(); terminado = false; for (int j = 0; j < numClases && !terminado; j++) { if (claseMt.esIgual((Atributo) listaClases.get(j))) { terminado = true; contadores[j]++; } } } } for (int i = 0; i < numClases; i++) { if (contadores[i] > actual) { mejor = i; actual = contadores[i]; } } clase = (Atributo) listaClases.get(mejor); return clase; } /** * Funcion que devuelve el numero de muestras cubiertas en el conjunto de * entrenamiento por la regla que se pasa por parametro. * @param regla Regla Regla a la que se le buscan sus muestras cubiertas * @return int Numero de muestras cubiertas por la regla. */ private int muestrasCubiertasPor(Regla regla) { int numeroCubiertas = 0; int numeroMuestras = cTrain.tamanio(); Muestra mt; Atributo clase = regla.obtenerReglaPredicha(); for (int i = 0; i < numeroMuestras; i++) { mt = cTrain.obtenerMuestra(i); if (regla.estanAtributosEn(mt) && mt.estaClase(clase)) { numeroCubiertas++; } } return numeroCubiertas; } /** * Funcion que devuelve el siguiente atributo fijandose en las reglas de probabilidad y * de feromona,se escoge para insertar en la regla que se esta creando * @param generadorA Randomize Generador de numeros aleatoreos * @param regla Regla Regla en la que se insertaria el siguiente atributo * @return Atributo Atributo escogido */ private Atributo escogeSiguienteAtributo(Randomize generadorA, Regla regla) { Atributo devolver; double probabilidadEscoger = 0; double probabilidadAcumulada = 0; boolean encontrado = false; boolean esta; int atributo = 0; int valor = 0; int numValores; int numAtributosRestantes = listaValoresRestantes.size(); Vector aux; probabilidadEscoger = generadorA.Rand(); //Double entre (0,1) //Calculamos la probabilidad de los atributos que quedan por coger atributo = 0; while (atributo < numAtributos && !encontrado) { aux = (Vector) listaValoresRestantes.get(atributo); //if(aux!=null){//En caso de que este atributo no este usado numValores = numeroValores[atributo]; valor = 0; while (valor < numValores && !encontrado) { probabilidadAcumulada = probabilidadAcumulada + probabilidad(atributo, valor, regla); if (probabilidadAcumulada >= probabilidadEscoger) { encontrado = true; } else { valor++; } } //while // }//if if (!encontrado) { atributo++; } } //while if (atributo != numAtributos) { aux = (Vector) listaValoresRestantes.get(atributo); } else { aux = new Vector(); } if (atributo == numAtributos || aux == null) { //Es el ultimo entonces!!!!!!!! atributo--; //Cogemos el ultimo atributo if (atributo < 0) { //Modulo para los numeros negativos atributo = numAtributos - 1; } valor = numeroValores[atributo] - 1; //Cogemos el ultimo valor while ((Vector) listaValoresRestantes.get(atributo) == null) { atributo--; //Cogemos el ultimo atributo if (atributo < 0) { //Modulo para los numeros negativos atributo = numAtributos - 1; } valor = numeroValores[atributo] - 1; //Cogemos el ultimo valor } //System.out.print("Error al escoger Atributo: "); //System.out.println(probabilidadEscoger + " " + probabilidadAcumulada+" "+atributo+" "+valor); } aux = (Vector) listaValores.get(atributo); devolver = (Atributo) aux.get(valor); return devolver; } /** * Funcion que devuelve la probabilidad de escoger un valor para el * atributo que se pasan por parametro * * @param atributo int Atributo al que se le quiere asignar valor * @param valor int Valor que se asignaria al atributo * @param regla Regla Regla en la que se estan insertando los atributos * @return double Probabilidad de que la hormiga los elija para la regla */ private double probabilidad(int atributo, int valor, Regla regla) { double probabilidad = 0; double nij; double denominadorNij; double numeradorNij; double valoresSinUsarNij; double nijDenominador; double tijDenominador; double tij; double denominador = 0; double numerador = 0; int numClases = listaClases.size(); int numValores; boolean esta; //-----------------------Eficiencia----------------- denominadorNij = funcionN[atributo][valor]; valoresSinUsarNij = valoresSinUsarNij(regla); denominadorNij = denominadorNij - valoresSinUsarNij; numeradorNij = Math.log(listaClases.size()) / Math.log(2); numeradorNij = numeradorNij - funcionH[atributo][valor]; //------------------------------------------------------- nij = numeradorNij / denominadorNij; tij = feromona[atributo][valor]; numerador = nij * tij; //Calculo del denominador for (int i = 0; i < numAtributos; i++) { esta = regla.tieneValorAtributo(i); if (!esta) { //Si no esta el atributo i sumamos numValores = numeroValores[i]; for (int j = 0; j < numValores; j++) { //-----------------------Eficiencia----------------- denominadorNij = funcionN[i][j]; denominadorNij = denominadorNij - valoresSinUsarNij; numeradorNij = Math.log(listaClases.size()) / Math.log(2); numeradorNij = numeradorNij - funcionH[i][j]; //------------------------------------------------------- nijDenominador = numeradorNij / denominadorNij; tijDenominador = feromona[i][j]; denominador += (nijDenominador * tijDenominador); } //for2 } //if } //for1 if (denominador == 0 || numerador == 0) { //Intentamos evitar el NAN probabilidad = 0; } else { probabilidad = numerador / denominador; } if (Double.isInfinite(probabilidad) || Double.isNaN(probabilidad)) { System.out.println("Probabilidad: " + numerador + " " + denominador + " " + nij + " " + tij); } return probabilidad; } float valoresSinUsarNij(Regla regla) { Vector condiciones = regla.listaCondiciones(); Vector valores; Atributo atributo; int pos; int max; float devolver = 0; double logK = Math.log(listaClases.size()) / Math.log(2); for (int i = 0; i < condiciones.size(); i++) { atributo = (Atributo) condiciones.get(i); pos = atributo.getAtributo(); max = numeroValores[pos]; for (int j = 0; j < max; j++) { devolver += (float) (logK - funcionH[pos][j]); } } return devolver; } /** * Funcion que calcula el valor de la funcion Heuristica * @param atributo int Atributo que se desea calcular * @param valor int Valor del atributo * @return double Valor de la funcion Heuristica */ private float calculaNij(int atributo, int valor) { float devolver = 0; float acumulador = 0; int nValores; boolean esta; int numClases = listaClases.size(); //k double probabilidadWAij = funcionH[atributo][valor]; //H(W|Ai=Vij); double logK = Math.log(numClases) / Math.log(2); //log2(k) float denominador = 0; for (int i = 0; i < numAtributos; i++) { //Construccion del denominador nValores = numeroValores[i]; //Tomamos los distintos valores que puede tomar el atributo //if(!regla.tieneValorAtributo(i)) for (int j = 0; j < nValores; j++) { acumulador += (logK - funcionH[i][j]); } } //for denominador = acumulador; if (denominador != 0) { devolver = (float) denominador; } else { devolver = 0; } return devolver; }; /** * Funcion que obtiene la Entropia para un valor de un atributo dado. * @param atributo int Atributo del que se quiere calcular la entropia. * @param valor int Valor del atributo. * @return float Valor de entropia para el valor del atributo. */ private float obtenerFuncionH(int atributo, int valor) { float devolver = 0; float[] probabilidades; Vector valores; Atributo Aij; Atributo W; float sumatoria; float probabilidad; boolean aparece = false; //Aparece el atributo en alguna muestra //Se coge el atributo que interviene en la funcion valores = (Vector) listaValores.get(atributo); Aij = (Atributo) valores.get(valor); //Valor de k en la funcion int numClases = listaClases.size(); //Diferentes valores para las clases //Vector con todas las muestras que contienen el atributo Aij probabilidades = cTrain.listaProbabilidadesAtributoClase(Aij, listaClases); //Modificar el modulo para hacerlo todo de una tacada for (int i = 0; i < numClases; i++) { probabilidad = probabilidades[i]; //Probabilidad if (probabilidad != 0) { //Si probabilidad es 0 el logaritmo da infinito sumatoria = (float) (Math.log(probabilidad) / Math.log(2.0)); //Calculamos el logaritmo2 de la probabilidad sumatoria = sumatoria * probabilidad; //Multiplicamos el logaritmo por la probabilidad devolver = devolver + sumatoria; //Sumatoria de probabilidades aparece = true; } } //Cambio de signo ya que es -Sumatoria devolver = 0 - devolver; if (!aparece) { //Si no aparece en ningun lado se inicializa a log2(k) devolver = (float) (Math.log(listaClases.size()) / Math.log(2)); } return devolver; } /** * Funcion que calcula la probabilidad de que la clase sea W si el atributo es Aij * @param muestras Vector Vector con las muestras donde se desea buscar la probabilidad * @param clase Atributo Clase W * @param valor Atributo Atributo Aij * @return double Probabilidad calculada. */ private double probabilidadWAij(Vector muestras, Atributo clase, Atributo valor) { double devolver = 0; int total = muestras.size(); int muestrasWAij = 0; Muestra mt; for (int i = 0; i < muestras.size(); i++) { mt = (Muestra) muestras.get(i); if (mt.estaAtributo(valor) && mt.estaClase(clase)) { //Si tenemos el atributo y la clase contenidos muestrasWAij++; } } devolver = muestrasWAij / total; return devolver; } /** * Modulo que crea la matriz de feromona inicializandola con los valores * iniciales propuestos por el algoritmo */ private void creaMatrizFeromona() { float valorInicial; float numeroTotalValores = 0; Vector array; Vector atributo; int tamanio; for (int i = 0; i < numAtributos; i++) { array = (Vector) listaValores.get(i); numeroTotalValores = numeroTotalValores + array.size(); } valorInicial = 1 / numeroTotalValores; feromona = new float[numAtributos][]; for (int i = 0; i < numAtributos; i++) { array = (Vector) listaValores.get(i); //Obtenemos un puntero al vector con los distintos valores de este atributo tamanio = array.size(); feromona[i] = new float[tamanio]; for (int j = 0; j < tamanio; j++) { feromona[i][j] = valorInicial; } } } /** * Modulo que imprime las dos listas creadas con los valores y clases * posibles */ private void imprimeListas() { System.out.println("Lista con distintos valores para cada atributo"); Vector auxiliar; Atributo at; for (int i = 0; i < numAtributos; i++) { System.out.println("Atributo: " + i); auxiliar = (Vector) listaValores.get(i); for (int j = 0; j < auxiliar.size(); j++) { at = (Atributo) auxiliar.get(j); System.out.print("\t" + at.getValor()); } System.out.println(); } System.out.println(); System.out.println("Lista con distintos valores para la clase"); for (int i = 0; i < listaClases.size(); i++) { at = (Atributo) listaClases.get(i); System.out.println("\t" + at.getValor()); } System.out.println(); } }