/*********************************************************************** 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.Decision_Trees.DT_GA; /** * <p>Title: </p> * * <p>Description: </p> * * <p>Copyright: Copyright (c) 2007</p> * * <p>Company: </p> * * @author not attributable * @version 1.0 */ import java.util.ArrayList; import org.core.Randomize; public class Individuo implements Comparable { Selector[] antecedente; boolean[] seleccionado; String clase; myDataset train; double fitness; boolean n_e; int codigoRegla; public Individuo() { antecedente = new Selector[1]; antecedente[0] = new Selector(); seleccionado = new boolean[1]; n_e = true; } public Individuo(boolean[] antecedentes, String clase, myDataset train, int codigo) { this.clase = clase; this.train = train; antecedente = new Selector[antecedentes.length]; seleccionado = new boolean[antecedentes.length]; seleccionado = antecedentes.clone(); for (int i = 0; i < antecedentes.length; i++) { if (seleccionado[i]) { antecedente[i] = new Selector(i, train); //lo genera aleatorio } } n_e = true; codigoRegla = codigo; } public Individuo(myDataset train, int pos_ejemplo) { this.clase = "?"; //se escoge dinamicamente this.train = train; antecedente = new Selector[train.getnInputs()]; seleccionado = new boolean[train.getnInputs()]; double [] ejemplo = train.getExample(pos_ejemplo); for (int i = 0; i < seleccionado.length; i++) { /*if (Randomize.Rand() < 0.5){ seleccionado[i] = true; }else{ seleccionado[i] = false; }*/ seleccionado[i] = true; } for (int i = 0; i < antecedente.length; i++) { //if (seleccionado[i]) { antecedente[i] = new Selector(i, train); //lo genera aleatorio //} if (!antecedente[i].cubre(ejemplo)){ //Hago los cambios para que lo cubra antecedente[i].modifica(ejemplo); } } n_e = true; } public Individuo(Individuo padre, Individuo madre, int puntoCorte) { antecedente = new Selector[padre.size()]; seleccionado = new boolean[padre.size()]; for (int i = 0; i < puntoCorte; i++) { seleccionado[i] = padre.seleccionado[i]; if (seleccionado[i]) { antecedente[i] = padre.antecedente[i].copia(); } } for (int i = puntoCorte; i < madre.size(); i++) { seleccionado[i] = madre.seleccionado[i]; if (seleccionado[i]) { antecedente[i] = madre.antecedente[i].copia(); } } /*int contador = 0; for (int i = 0; i < seleccionado.length; i++){ if (!seleccionado[i]) contador++; } if (contador == seleccionado.length-1){ System.err.println("OUCH!!"); System.exit(-1); }*/ this.clase = padre.clase; //en GA_large se define dinamicamente this.train = padre.train; fitness = 0.0; codigoRegla = padre.codigoRegla; n_e = true; } public String printString() { String cadena = new String(""); cadena += "IF "; for (int i = 0; i < antecedente.length; i++) { if (seleccionado[i]) { cadena += antecedente[i].printString() + "AND "; } } cadena += " THEN Class = " + clase + "\n"; return cadena; } /** * Convierte al cromosoma en una regla valida * @return Regla la regla creada */ public Regla convertir() { Regla r = new Regla(); r.antecedente = new ArrayList<Selector> (); for (int i = 0; i < antecedente.length; i++) { if (seleccionado[i]) { r.antecedente.add(antecedente[i].copia()); } } r.clase = clase; r.train = train; r.ejemplosCubiertos = new int[train.size()]; r.nCubiertos = 0; r.ejemplosBienCubiertos = new int[train.size()]; r.nCubiertosOK = 0; r.fitness = this.fitness; r.codigoRegla = this.codigoRegla; r.cubrirEjemplos(); return r; } public Individuo clone() { Individuo ind = new Individuo(); ind.seleccionado = new boolean[this.seleccionado.length]; ind.seleccionado = this.seleccionado.clone(); ind.antecedente = new Selector[this.antecedente.length]; for (int i = 0; i < this.antecedente.length; i++) { if (seleccionado[i]) { ind.antecedente[i] = this.antecedente[i].copia(); } } ind.clase = this.clase; ind.fitness = this.fitness; ind.train = this.train; ind.n_e = this.n_e; ind.codigoRegla = this.codigoRegla; return ind; } public double clasifica(int[] ejemplos, int nEjemplos) { int tp, fn, tn, fp; tp = fn = tn = fp = 0; //teoricamente fitness = (tp/(tp+fn))*(tn/(fp+tn)); pero... boolean algunoCubierto = false; for (int j = 0; j < nEjemplos; j++) { boolean cubierto = true; boolean completo = false; double[] ejemplo = train.getExample(ejemplos[j]); for (int i = 0; (i < antecedente.length) && (cubierto); i++) { if (seleccionado[i]) { completo = true; cubierto = cubierto && (antecedente[i].cubre(ejemplo)); } } cubierto = cubierto && completo; //si no tiene ningun antecedente no me vale! String clase = train.getOutputAsString(ejemplos[j]); if (cubierto) { algunoCubierto = true; if (clase.equalsIgnoreCase(this.clase)) { tp++; } else { fp++; } } else { if (clase.equalsIgnoreCase(this.clase)) { fn++; //inventada julian } else { tn++; //inventada julian } } } //System.err.println("Cromosoma: " + this.printString() + " Mira -> Tn: " + // tn + " Tp: " + tp + " Fn: " + fn + " Fp:" + fp); if (!algunoCubierto){ tp = tn = fp = fn = 0; } double sens = 1.0; if (tp + fn > 0) { sens = (1.0 * tp / (tp + fn)); } double spec = 1.0; if (tn + fp > 0) { spec = (1.0 * tn / (fp + tn)); } if (tp + tn == 0) { sens = spec = 0; } n_e = false; fitness = sens * spec; return fitness; } public double clasificaLarge(int[] ejemplos, int nEjemplos) { int tp, fn, tn, fp; tp = fn = tn = fp = 0; //teoricamente fitness = (tp/(tp+fn))*(tn/(fp+tn)); pero... int nClases = train.getnClasses(); int[] cubiertosClase = new int[nClases]; boolean[] cubiertos = new boolean[train.size()]; for (int j = 0; j < nEjemplos; j++) { boolean cubierto = true; boolean completo = false; double[] ejemplo = train.getExample(ejemplos[j]); for (int i = 0; (i < antecedente.length) && (cubierto); i++) { if (seleccionado[i]) { completo = true; cubierto = cubierto && (antecedente[i].cubre(ejemplo)); } } cubierto = cubierto && completo; if (cubierto) { int clase = train.getOutputAsInteger(ejemplos[j]); cubiertosClase[clase]++; } cubiertos[j] = cubierto; } int maxCubiertos = 0; for (int i = 0; i < nClases; i++) { if (cubiertosClase[i] > maxCubiertos) { maxCubiertos = cubiertosClase[i]; this.clase = train.nombreClase(i); } } if (maxCubiertos > 0) { for (int i = 0; i < train.size(); i++) { String clase = train.getOutputAsString(i); if (cubiertos[i]) { if (clase.equalsIgnoreCase(this.clase)) { tp++; } else { fp++; } } else { if (clase.equalsIgnoreCase(this.clase)) { fn++; //inventada julian } else { tn++; //inventada julian } } } //System.err.println("Cromosoma: " + this.printString() + " Mira -> Tn: " + // tn + " Tp: " + tp + " Fn: " + fn + " Fp:" + fp); } double sens = 1.0; if (tp + fn > 0) { sens = (1.0 * tp / (tp + fn)); } double spec = 1.0; if (tn + fp > 0) { spec = (1.0 * tn / (fp + tn)); } if (tp + tn == 0) { sens = spec = 0; } n_e = false; fitness = sens * spec; return fitness; } public int size() { return antecedente.length; } /** * Esta funcion me la invento...tomaya!! * @param mutProb probabilidad de mutacion */ public void mutar(double mutProb) { for (int i = 0; i < antecedente.length; i++) { if ( (seleccionado[i]) && (Randomize.Rand() < mutProb)) { antecedente[i].mutar(); } } } /** * Calcula la ganancia de informacion * @param atributo int atributo a considerar * @param ejemplos son los ejemplos de entrenamiento considerados * @param T int Numero de ejemplos de entrenamiento * @return double la ganancia * * Info(G|cond_i) = [ - (|Vi|/|T|)*sum_{j=1}^c{(|Vij|/|Vi|)*(log_2{|Vij|/|Vi|})} * - (|�Vi|/|T|)*sum_{j=1}^c{(|�Vij|/|�Vi|)*(log_2{|�Vij|/|�Vi|})} * * |Vi| = numero de ejemplos que satisfacen la condicion <Ai OPi Vij> * |Vij| = numero de ejemplos que satisfacen la condicion <Ai OPi Vij> y tienen el valor j para la clase * |�Vi| = numero de ejemplos que NO satisfacen la condicion <Ai OPi Vij> * |�Vij| = numero de ejemplos que NO satisfacen la condicion <Ai OPi Vij> y tienen el valor j para la clase */ private double infoGcondi(int atributo, int[] ejemplos, int T) { double info = 0; int Vi, Vij[], noVi, noVij[]; Vi = noVi = 0; Vij = new int[train.getnClasses()]; noVij = new int[train.getnClasses()]; for (int i = 0; i < Vij.length; i++) { Vij[i] = noVij[i] = 0; } for (int j = 0; j < T; j++) { double[] ejemplo = train.getExample(ejemplos[j]); boolean cubierto = (antecedente[atributo].cubre(ejemplo)); int clase = train.getOutputAsInteger(ejemplos[j]); if (cubierto) { Vi++; Vij[clase]++; } else { noVi++; noVij[clase]++; } } double sum1, sum2; sum1 = sum2 = 0; for (int i = 0; i < Vij.length; i++) { //Para las c clases double aux = 1.0 * Vij[i] / Vi; sum1 += (aux) * (Math.log(aux) / Math.log(2)); aux = 1.0 * noVij[i] / noVi; sum2 += (aux) * (Math.log(aux) / Math.log(2)); } sum1 *= 1.0 * Vi / T; sum2 *= 1.0 * noVi / T; info = -sum1 - sum2; return info; } public void pruning(double infoG, int nEjemplos, int[] ejemplos) { double[] info_gain = new double[antecedente.length]; int[] atributos = new int[antecedente.length]; int n = 0; for (int i = 0; i < antecedente.length; i++) { //calculo la ganancia de cada atributo atributos[i] = i; if (seleccionado[i]) { info_gain[i] = infoG - infoGcondi(i, ejemplos, nEjemplos); n++; } } if (n > 2) { //2 es el minimo numero de antecedentes permitido //Ordeno de menor a mayor la informacion (y los atributos) for (int i = 0; i < antecedente.length - 1; i++) { if (seleccionado[i]) { for (int j = i + 1; j < antecedente.length; j++) { if (seleccionado[j]) { if (info_gain[i] > info_gain[j]) { double temp = info_gain[i]; info_gain[i] = info_gain[j]; info_gain[j] = temp; int temp2 = atributos[i]; atributos[i] = atributos[j]; atributos[j] = temp2; } } } } } //Ahora pongo o quito antecedentes for (int i = 0; (i < antecedente.length) && (n > 2); i++) { if (seleccionado[i]) { if (Randomize.Rand() > info_gain[i]) { seleccionado[i] = false; n--; } } } } } public void pruning(double[] norm_acc) { int[] atributos = new int[antecedente.length]; int n = 0; for (int i = 0; i < antecedente.length; i++) { atributos[i] = i; if (seleccionado[i]) { n++; } } if (n > 2) { //2 es el minimo numero de antecedentes permitido //Ordeno de menor a mayor la informacion (y los atributos) for (int i = 0; i < antecedente.length - 1; i++) { if (seleccionado[i]) { for (int j = i + 1; j < antecedente.length; j++) { if (seleccionado[j]) { if (norm_acc[i] > norm_acc[j]) { double temp = norm_acc[i]; norm_acc[i] = norm_acc[j]; norm_acc[j] = temp; int temp2 = atributos[i]; atributos[i] = atributos[j]; atributos[j] = temp2; } } } } } //Ahora pongo o quito antecedentes for (int i = 0; (i < antecedente.length) && (n > 2); i++) { if (seleccionado[i]) { if (Randomize.Rand() > norm_acc[i]) { seleccionado[i] = false; n--; } } } } } public int compareTo(Object a) { if ( ( (Individuo) a).fitness < this.fitness) { return -1; } if ( ( (Individuo) a).fitness > this.fitness) { return 1; } return 0; } }